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

bvhaajcl  于 2023-11-14  发布在  其他
关注(0)|答案(6)|浏览(133)

我有一个csv文件,其中的一行数据可能看起来像这样:
10,“苹果,香蕉”,20,.
当我在Python中加载数据时,引号内的额外逗号会移动我所有的列索引,因此我的数据不再是一个一致的结构。虽然我可能会编写一个复杂的算法来迭代每一行并解决这个问题,我希望有一种优雅的方法,只需要向loadtxt传递一个额外的参数(或其他函数),它将正确地忽略引号内的逗号,并将整个引号视为一个值。
请注意,当我将CSV文件加载到Excel中时,Excel会将该字符串正确识别为一个值。

up9lanfz

up9lanfz1#

使用一个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')])

doinxwow

doinxwow2#

这个问题之前已经讨论过了。在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')
fdx2calv

fdx2calv3#

我用下面的代码解决了这个问题。

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

fumotvh3

fumotvh34#

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

bwntbbo3

bwntbbo35#

虽然numpy.loadtxt中没有这样的参数来忽略引号或转义逗号,但还没有建议的一种替代方案是以下...
执行查找和替换使用一些文本编辑器替换逗号与制表符或保存文件在Excel中作为制表符分隔。
当您使用numpy.loadtxt时,您只需指定delimiter='\t'而不是逗号分隔。
简单的解决方案,可以保存你一些代码.

odopli94

odopli946#

从numpy 1.23.0版本开始,您现在可以使用参数quotechar来实现此效果。
你可以这样使用它:

data = np.loadtxt("data.csv", delimiter=",", dtype=str, quotechar='"')

字符串
来自numpy.loadtext的文档:

quotechar:unicode字符或None,可选

用于表示引用项的开始和结束的字符。引用项中出现的引号或注解字符将被忽略。默认值为quotechar=None,表示禁用引用支持。
如果在一个带引号的字段中发现两个连续的quotechar示例,则第一个被视为转义字符。

相关问题