这个问题之前已经讨论过了。 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')]
元组列表正是结构化数组所需要的。
没有花哨的处理、错误检查或评论行过滤。只是模式匹配,然后是数组构造。
我的foo 和fromregex 都假设一个特定的数字序列和带引号的字符串。 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')