【问题标题】:Pandas CParserError: Error tokenizing dataPandas CParserError:错误标记数据
【发布时间】:2016-08-23 05:57:47
【问题描述】:

我有一个包含 25 列的大型 csv 文件,我想将其读取为 pandas 数据框。我正在使用pandas.read_csv()。 问题是有些行有额外的列,像这样:

        col1   col2   stringColumn   ...   col25
1        12      1       str1                 3
...
33657    2       3       str4                 6       4    3 #<- that line has a problem
33658    1      32       blbla                 #<-some columns have missing data too 

当我尝试阅读它时,我得到了错误

CParserError: Error tokenizing data. C error: Expected 25 fields in line 33657, saw 28

如果额外的值出现在第一行中,则不会发生此问题。例如,如果我将值添加到同一文件的第三行,它可以正常工作

#that example works: 
           col1   col2   stringColumn   ...   col25
    1        12      1       str1                 3
    2        12      1       str1                 3
    3        12      1       str1                 3       f    4
    ...
    33657    2       3       str4                 6       4    3 #<- that line has a problem
    33658    1      32       blbla                 #<-some columns have missing data too 

我的猜测是,pandas 会检查前 (n) 行以确定列数,如果之后有额外的列,它会在解析它时出现问题。

跳过像建议的here 这样的违规行不是一种选择,这些行包含有价值的信息。

有人知道解决这个问题的方法吗?

【问题讨论】:

  • 您希望这些行如何存储和表示?例如,您是在 25 列还是 28 列之后?
  • 我只对 25 列中的大约一半感兴趣。额外列中的值我不感兴趣。
  • 列数是否固定?即它总是 28
  • 你不能只做pd.read_csv(file_path, delim_whitespace=True, usecols=np.arange(25))吗?
  • 我尝试了data = pd.read_csv(f, skiprows=2, delimiter="\t", dtype='str', index_col=0, usecols=np.arange(25)) 并得到了ValueError: Usecols do not match names。 (字段由 \t 分隔,并且在开头多出一行,因此参数 skiprowsdelimiter

标签: python csv pandas


【解决方案1】:

由于我没有找到完全解决问题的答案,所以这是我的解决方法:我发现使用选项 names=('col1', 'col2', 'stringColumn' ... 'column25', '', '', '') 显式传递列名可以让我读取文件。它迫使我读取和解析每一列,这并不理想,因为我只需要其中的一半,但至少我现在可以读取文件。 结合参数 namesusecols 并不起作用,如果有人有其他解决方案,我会很高兴听到它。

【讨论】:

    【解决方案2】:

    在我最初的帖子中,我提到在 pandas.read_csv 中不使用“error_bad_lines” = False。我认为实际上这样做是更合适和优雅的解决方案。我发现这篇文章非常有用。

    Can I redirect the stdout in python into some sort of string buffer?

    我对答案中显示的代码进行了一些改动。

    import sys
    import re
    from cStringIO import StringIO
    import pandas as pd
    
    fake_csv = '''1,2,3\na,b,c\na,b,c\na,b,c,d,e\na,b,c\na,b,c,d,e\na,b,c\n''' #bad data
    fname = "fake.csv"
    old_stderr = sys.stderr
    sys.stderr = mystderr = StringIO()
    
    df1 = pd.read_csv(StringIO(fake_csv),
                      error_bad_lines=False)
    
    sys.stderr = old_stderr 
    log = mystderr.getvalue()
    isnum = re.compile("\d+")
    
    lines_skipped_log = [
        isnum.findall(i) + [fname]\
        for i in log.split("\n") if isnum.search(i)
            ]
    
    columns=["line_num","flds_expct","num_fields","file"]
    lines_skipped_log.insert(0,columns)
    

    从那里您可以使用lines_skipped_log 做任何您想做的事情,例如输出到 csv、创建数据框等。

    也许你有一个充满文件的目录。您可以从每个日志中创建一个 pandas 数据帧列表并进行连接。从那里您将获得一个日志,记录哪些行被跳过以及哪些文件触手可及(字面意思!)。

    【讨论】:

      【解决方案3】:

      一种可能的解决方法是指定列名。请参考我对类似问题的回答:https://stackoverflow.com/a/43145539/6466550

      【讨论】:

        猜你喜欢
        • 2016-09-27
        • 1970-01-01
        • 2013-08-05
        • 1970-01-01
        • 1970-01-01
        • 2019-08-06
        • 1970-01-01
        相关资源
        最近更新 更多