2010-04-19 82 views
9

我有一個CSV,看起來像這樣的格式文件:在numpy的閱讀CSV文件,其中分隔符 「」

「FieldName1」, 「FieldName2」, 「FieldName3」, 「FieldName4」
「04/13/2010 14:45:07.008」,「7.59484916392」,「10」,「6.552373」
「2010年4月13日14:45:22.010」,「6.55478493312」,「9」 3.5378543"
...

注意,有在第t每行的開始和結束的雙引號字符他CSV文件和","字符串用於分隔每行內的字段。 CSV文件中的字段數可因文件而異。

當我嘗試通過讀入numpy的是:
import numpy as np
data = np.genfromtxt(csvfile, dtype=None, delimiter=',', names=True)
所有數據被讀取爲字符串值,由雙引號字符包圍。不是沒有道理,但沒多大用的我,因爲我接下來要回去和每列轉換爲它的正確類型

當我使用delimiter='","'代替,一切正常,因爲我想,除了第一和最後一個領域。由於行首和行尾字符是單個雙引號字符,因此不會將其視爲第一個和最後一個字段的有效分隔符,因此它們會被讀入爲例如。 "04/13/2010 14:45:07.0086.552373" - 分別注意前導和尾隨雙引號字符。由於這些冗餘字符,numpy假定第一個和最後一個字段都是字符串類型;我不希望這是這種情況

有沒有辦法指示numpy讀取格式化爲這種方式的文件,我想,而不必返回並「修復」numpy數組的結構初次閱讀後?

回答

12

基本問題是,NumPy不理解剝離引號的概念(而csv模塊)。當你說delimiter='","'時,你告訴NumPy,列分隔符實際上是一個帶引號的逗號,即引號是在逗號周圍,而不是值,因此可以期望獲得第一列和最後一列的額外引號。

綜觀功能的文檔,我想你會需要設置converters參數剝離報價爲您(默認沒有):

import re 
import numpy as np 

fieldFilter = re.compile(r'^"?([^"]*)"?$') 
def filterTheField(s): 
    m = fieldFilter.match(s.strip()) 
    if m: 
     return float(m.group(1)) 
    else: 
     return 0.0 # or whatever default 

#... 

# Yes, sorry, you have to know the number of columns, since the NumPy docs 
# don't say you can specify a default converter for all columns. 
convs = dict((col, filterTheField) for col in range(numColumns)) 
data = np.genfromtxt(csvfile, dtype=None, delimiter=',', names=True, 
    converters=convs) 

或放棄np.genfromtxt()csv.csvreader給你文件的內容排在同一時間,作爲字符串列表,那麼你只需要通過迭代的元素,並建立矩陣:

reader = csv.csvreader(csvfile) 
result = np.array([[float(col) for col in row] for row in reader]) 
# BTW, column headings are in reader.fieldnames at this point. 

編輯:好的,所以它看起來像你的文件是不是所有的花車。在這種情況下,你可以設置convs根據需要在genfromtxt情況下,或者在csv.csvreader情況下創建的轉換函數的向量:

reader = csv.csvreader(csvfile) 
converters = [datetime, float, int, float] 
result = np.array([[conv(col) for col, conv in zip(row, converters)] 
    for row in reader]) 
# BTW, column headings are in reader.fieldnames at this point. 

編輯2:好,可變列數...您的數據源只是想讓生活變得困難。幸運的是,我們可以使用magic ...

reader = csv.csvreader(csvfile) 
result = np.array([[magic(col) for col in row] for row in reader]) 

...其中magic()只是一個名字,我得到了我的頭一個函數的頂部。 (!琪)

在最壞情況下,它可能是這樣的:

def magic(s): 
    if '/' in s: 
     return datetime(s) 
    elif '.' in s: 
     return float(s) 
    else: 
     return int(s) 

也許NumPy的具有如下功能:接受一個字符串,並返回正確類型的單個元素。 numpy.fromstring()看起來很接近,但它可能會將時間戳中的空格解釋爲列分隔符。

P.S. csvreader我看到的一個缺點是它不放棄評論;真實csv文件沒有評論。

+1

如果輸入文件很大(很多MB或GB),'str.replace(''','')'方法的執行速度應該比正則表達式快得多,如果你能假設'' '字符不會出現在字段的中間,只在末尾出現。 – gotgenes 2010-04-19 02:29:28

+0

感謝Mike和gotgenes,但我也應該提到CSV文件具有可變數量的列。我可以使用上面描述的方法,通過添加一個初始步驟來讀取文件的第一個記錄來確定列的數量,然後將它用作後面步驟的輸入,但它看起來非常笨重。 有沒有更好的方法? – monch1962 2010-04-19 02:46:57

+0

小注:你不需要使用're.compile()',因爲直接使用re.match()直接緩存已編譯的正則表達式。 – blokeley 2010-04-19 07:42:18