2015-02-11 274 views
4

我有一個CSV文件,其中數據線可能是這樣的:numpy.loadtxt:如何忽略出現在引號內的逗號分隔符?

10,「蘋果,香蕉」,20,...

當我加載在Python的數據,額外的逗號內引號將我所有的列索引都移動了,所以我的數據不再是一個一致的結構。雖然我可能會編寫一個複雜的算法來遍歷每行並修復問題,但我希望有一種優雅的方法可以將一個額外的參數傳遞給loadtxt(或其他函數),以便正確忽略引號內的逗號並將整個報價作爲一個價值。

請注意,當我將CSV文件加載到Excel中時,Excel將該字符串正確識別爲一個值。

+0

你使用Python的CSV模塊加載試過? – Marcin 2015-02-11 00:20:23

回答

0

您可以使用Python CSV模塊:https://docs.python.org/2/library/csv.html

鑑於CSV格式的數據文件:

10,"Apple,Banana",20 
20,"Orange,Watermelon",30 

有了這個腳本:

from csv import reader 

with open('data.csv') as f: 
    for row in reader(f): 
     print row 

你得到:

['10', 'Apple,Banana', '20'] 
['20', 'Orange,Watermelon', '30'] 

由於loadtxt需要一個迭代,通過它reader(f)

with open('data.csv') as f: 
    data = loadtxt(reader(f), ...) 
+0

'loadtxt(reader(f)...)'不起作用,因爲'loadtxt'想要一個返回字符串的iterable。 'reader()'產生一個列表列表。你需要'加入':'(';'。join(x)for x in reader(f))''。 – hpaulj 2015-02-12 17:16:01

1

這個問題已經被討論過。 loadtxt(或genfromtxt)中沒有任何參數可以滿足您的需求。換句話說,它不是引號敏感的。 pythoncsv模塊具有某種報價意識。 pandas閱讀器也是引用意識。

但是在將它們傳遞給loadtxt之前處理這些行是完全可以接受的。所有的功能需求都是可迭代的 - 一次可以提供一條線。這可以是文件,行列表或生成器。

一個簡單的處理器只會用一些其他字符替換引號內的逗號。或用您選擇的分隔符替換引號外的那些。它不一定是想做這項工作。

Using numpy.genfromtxt to read a csv file with strings containing commas

例如:

txt = """10,"Apple, Banana",20 
30,"Pear, Orange",40 
50,"Peach, Mango",60 
""" 

def foo(astr): 
    # replace , outside quotes with ; 
    # a bit crude and specialized 
    x = astr.split('"') 
    return ';'.join([i.strip(',') for i in x]) 

txt1 = [foo(astr) for astr in txt.splitlines()] 
txtgen = (foo(astr) for astr in txt.splitlines()) # or as generator 
# ['10;Apple, Banana;20', '30;Pear, Orange;40', '50;Peach, Mango;60'] 
np.genfromtxt(txtgen, delimiter=';', dtype=None) 

生產:

array([(10, 'Apple, Banana', 20), (30, 'Pear, Orange', 40), 
     (50, 'Peach, Mango', 60)], 
     dtype=[('f0', '<i4'), ('f1', 'S13'), ('f2', '<i4')]) 

我沒有重視np.fromregex之前。與genfromtxt相比,它非常簡單。與我的樣品txt使用我不得不使用一個字符串緩衝區:

s=StringIO.StringIO(txt) 
np.fromregex(s, r'(\d+),"(.+)",(\d+)', dtype='i4,S20,i4') 

它的行動提煉到:

pat=re.compile(r'(\d+),"(.+)",(\d+)'); dt=np.dtype('i4,S20,i4') 
np.array(pat.findall(txt),dtype=dt) 

它讀取整個文件(f.read()),並做了findall應該產生像這樣的列表:

[('10', 'Apple, Banana', '20'), 
('30', 'Pear, Orange', '40'), 
('50', 'Peach, Mango', '60')] 

元組列表正是結構化數組需要的。

沒有花哨的處理,錯誤檢查或過濾註釋行。只是模式匹配,然後是數組構造。


我的兩個foofromregex承擔數的特定序列和引用字符串。 csv.reader可能是最簡單的通用報價閱讀器。 join是必需的,因爲reader產生一個列表清單,而genfromtxt需要一個可迭代的字符串(它自己的'拆分')。

from csv import reader 
s=StringIO.StringIO(txt) 
np.genfromtxt((';'.join(x) for x in reader(s)), delimiter=';', dtype=None) 

生產

array([(10, 'Apple, Banana', 20), (30, 'Pear, Orange', 40), 
     (50, 'Peach, Mango', 60)], 
     dtype=[('f0', '<i4'), ('f1', 'S13'), ('f2', '<i4')]) 

或者在下面的fromregex例如,reader輸出也可以變成一個元組列表,並給np.array直接:

np.array([tuple(x) for x in reader(s)], dtype='i4,S20,i4') 
2

一個你能方式用單個numpy函數調用它會使用np.fromregex,它允許您使用Python的regular expression syntax來調整以任意方式查看文本文件的內容。例如:

np.fromregex('tmp.csv', r'(\d+),"(.+)",(\d+)', np.object) 

爲您提供:

array([['10', 'Apple, Banana', '20'], 
     ['30', 'Orange, Watermelon', '40']], dtype=object) 

爲了解開這個正則表達式一點,'(\d+)'將匹配一個或多個數字和'"(.+)"'將匹配一個或多個任意字符的雙引號內。 np.fromregex會嘗試在.csv文件的每一行內匹配此表達式,並將括號內的部分作爲輸出數組每一行中的各個元素。

如果你想有一個記錄陣列與在您.csv文件中的三個「列」不同「場」你的輸出,你可以指定在正則表達式每組支架單獨dtypes

np.fromregex('tmp.csv', r'(\d+),"(.+)",(\d+)', 'i8, S20, i8') 

給你:

array([(10, 'Apple, Banana', 20), (30, 'Orange, Watermelon', 40)], 
     dtype=[('f0', '<i8'), ('f1', 'S20'), ('f2', '<i8')]) 
1

我用下面的代碼解決了這個問題。

def transformCommas(line): 
    out = '' 
    insideQuote = False 
    for c in line: 
     if c == '"': 
      insideQuote = not insideQuote 
     if insideQuote == True and c == ',': 
      out += '.' 
     else: 
      out += c 
    return out 

f = open("data/raw_data_all.csv", "rb") 
replaced = (transformCommas(line) for line in f) 
rawData = numpy.loadtxt(replaced,delimiter=',', skiprows=0, dtype=str) 

數據:

1366x768,18,"5,237",73.38%,"3,843",79.55%,1.75,00:01:26,4.09%,214,$0.00 
1366x768,22,"5,088",76.04%,"3,869",78.46%,1.82,00:01:20,3.93%,200,$0.00 
1366x768,17,"4,887",74.34%,"3,633",78.37%,1.81,00:01:19,3.25%,159,$0.00