簡體   English   中英

numpy.loadtxt:如何忽略引號內出現的逗號分隔符?

[英]numpy.loadtxt: how to ignore comma delimiters that appear inside quotes?

我有一個 csv 文件,其中一行數據可能如下所示:

10,《蘋果、香蕉》,20,...

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

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

您可以使用單個 numpy 函數調用來完成的一種方法是使用np.fromregex ,它允許您使用 Python 的正則表達式語法以任意方式解析文本文件的內容。 例如:

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')])

這個問題之前已經討論過了。 loadtxt (或genfromtxt )中沒有可以執行您想要的操作的參數。 換句話說,它對引用不敏感。 python csv模塊具有某種報價意識。 pandas讀者也知道引用。

但是在將它們傳遞給loadtxt之前處理這些行是完全可以接受的。 所有函數需要的是一個可迭代的——可以一次一行地提供給它的東西。 所以它可以是一個文件、一個行列表或生成器。

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

使用 numpy.genfromtxt 讀取包含逗號的字符串的 csv 文件

例如:

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')

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

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

您可以使用 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), ...)

雖然 numpy.loadtxt 中沒有這樣的參數來忽略引用或以其他方式轉義的逗號,但尚未建議的一種替代方法是以下...

使用一些文本編輯器執行查找和替換,用制表符替換逗號或將文件保存在 Excel 中作為制表符分隔。

當您使用 numpy.loadtxt 時,您只需指定delimiter='\\t'而不是逗號分隔。

可以為您節省一些代碼的簡單解決方案......

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM