numpy.loadtxt:如何忽略出现在引号内的逗号分隔符?

时间:2015-02-11 00:08:19

标签: python csv numpy

我有一个csv文件,其中一行数据可能如下所示:

10,“Apple,Banana”,20,......

当我在Python中加载数据时,引号内的额外逗号会移动我的所有列索引,因此我的数据不再是一致的结构。虽然我可能会编写一个复杂的算法来遍历每一行并修复问题,但我希望有一种优雅的方法可以将额外的参数传递给loadtxt(或其他一些函数),这些参数将正确地忽略引号内的逗号并对待整个报价作为一个价值。

注意,当我将CSV文件加载到Excel中时,Excel会将字符串正确识别为一个值。

5 个答案:

答案 0 :(得分: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 :(得分:1)

此问题已在之前讨论过。 loadtxt(或genfromtxt)中没有符合您需要的参数。换句话说,它不是引用敏感的。 python csv模块具有某种引用意识。 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 :(得分: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

答案 3 :(得分: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), ...)

答案 4 :(得分:0)

虽然numpy.loadtxt中没有这样的参数可以忽略用引号引起来的或以其他方式转义的逗号,但尚未建议的替代方法如下:

执行查找并使用某些文本编辑器替换以制表符替换逗号 要么 在文件中以制表符分隔的格式保存文件。

使用numpy.loadtxt时,只需指定delimiter='\t'而不是逗号分隔。

简单的解决方案可以为您节省一些代码...