【问题标题】:Python Pandas Error tokenizing dataPython Pandas 错误标记数据
【发布时间】:2013-08-05 00:46:39
【问题描述】:

我正在尝试使用 pandas 来操作 .csv 文件,但出现此错误:

pandas.parser.CParserError:错误标记数据。 C 错误:预计第 3 行中有 2 个字段,看到 12

我尝试阅读 pandas 文档,但一无所获。

我的代码很简单:

path = 'GOOG Key Ratios.csv'
#print(open(path).read())
data = pd.read_csv(path)

我该如何解决这个问题?我应该使用csv 模块还是其他语言?

文件来自Morningstar

【问题讨论】:

  • 如果读取pandas.to_csv()写入的文件时出现此错误,可能是因为列名中有'\r',这种情况下to_csv()实际上会写入后续列名称进入数据框的第一列,导致前 X 行中的列数不同。这种差异是导致 C 错误的原因之一。
  • 有时只是明确地给出“sep”参数会有所帮助。似乎是解析器问题。
  • 当您使用逗号作为分隔符并且您的逗号比预期的多(错误行中的更多字段然后在标题中定义)时,也可能会出现此错误。因此,您需要删除附加字段或删除多余的逗号(如果错误存在)。您可以手动修复此问题,然后无需跳过错误行。
  • gilgamash 的评论帮助了我。在文本编辑器(如 Windows 编辑器或记事本++)中打开 csv 文件,查看用于分隔的字符。如果是分号,例如试试pd.read_csv("<path>", sep=";")。不要使用 Excel 进行检查,因为它有时会默认将数据放入列中,因此会删除分隔符。
  • 有类似的问题。意识到这是由于我的 csv 文件中有一个带有逗号的值。必须用 " " 封装它

标签: python csv pandas


【解决方案1】:

你也可以试试;

data = pd.read_csv('file1.csv', on_bad_lines='skip')

请注意,这将导致有问题的行被跳过。

【讨论】:

  • 偶然发现了这个答案,有没有办法在输出类似expected 8 fields, saw 9的行上填充缺失的列?
  • 更好的解决方案是调查有问题的文件并更正错误的行,以便read_csv 可以读取它们。 @PetraBarus,为什么不将列添加到缺少它们的 CSV 文件中(根据需要使用空值)?
  • 是的,我就是这么做的。通过添加列要容易得多。在电子表格中打开 CSV 会执行此操作。
  • 传入names=["col1", "col2", ...] 以获得预期列的最大数量也可以,这就是我遇到这个问题时解决这个问题的方法。见:stackoverflow.com/questions/18039057/…
  • 这不应该是公认的答案,会跳过行,你不知道为什么......
【解决方案2】:

我遇到了针对此问题的多种解决方案。很多人也对答案给出了最好的解释。但是对于初学者来说,我认为以下两种方法就足够了:

import pandas as pd

#Method 1

data = pd.read_csv('file1.csv', error_bad_lines=False)
#Note that this will cause the offending lines to be skipped.

#Method 2 using sep

data = pd.read_csv('file1.csv', sep='\t')

【讨论】:

    【解决方案3】:

    问题在于分隔符。找出您的数据中使用了哪种分隔符,并按如下方式指定:

    data = pd.read_csv('some_data.csv', sep='\t')
    

    【讨论】:

      【解决方案4】:

      这可能是个问题

      • 数据中的分隔符
      • 第一行,正如@TomAugspurger 所指出的那样

      要解决此问题,请尝试在调用 read_csv 时指定 sep 和/或 header 参数。例如,

      df = pandas.read_csv(filepath, sep='delimiter', header=None)
      

      在上面的代码中,sep 定义了您的分隔符,header=None 告诉 pandas 您的源数据没有标题/列标题行。因此 the docs 说:“如果文件不包含标题行,那么您应该显式传递 header=None”。在这种情况下,pandas 会自动为每个字段 {0,1,2,...} 创建整数索引。

      根据文档,分隔符应该是的问题。文档说“如果 sep 是 None [未指定],将尝试自动确定这一点。”但是,我对此并不满意,包括带有明显分隔符的实例。

      另一种解决方案可能是尝试自动检测分隔符

      # use the first 2 lines of the file to detect separator
      temp_lines = csv_file.readline() + '\n' + csv_file.readline()
      dialect = csv.Sniffer().sniff(temp_lines, delimiters=';,')
      
      # remember to go back to the start of the file for the next time it's read
      csv_file.seek(0) 
      
      df = pd.read_csv(csv_file, sep=dialect.delimiter)
      
      

      【讨论】:

        【解决方案5】:

        这看起来很难看,但你会有你的数据框

        import re
        path = 'GOOG Key Ratios.csv'
        
        try:
            data = pd.read_csv(path)
        except Exception as e:
            val = re.findall('tokenizing.{1,100}\s*Expected\s*(\d{1,2})\s*',str(e),re.I)
            data = pd.read_csv(path, skiprows=int(val[0])-1)
        

        【讨论】:

          【解决方案6】:

          有时在单元格中有一个逗号“,”。由于熊猫无法阅读它。 尝试使用“;”分隔符

          df = pd.read_csv(r'yourpath', delimiter=";")
          

          【讨论】:

            【解决方案7】:

            你可以试试;

            data = pd.read_csv('file1.csv', sep='\t')
            

            【讨论】:

            • 虽然此代码可能会解决问题,including an explanation 关于如何以及为什么解决问题将真正有助于提高您的帖子质量,并可能导致更多的赞成票。请记住,您正在为将来的读者回答问题,而不仅仅是现在提问的人。请edit您的答案以添加解释并说明适用的限制和假设。 From Review
            【解决方案8】:

            我相信解决方案,

            ,engine='python'
            , error_bad_lines = False
            

            如果它是虚拟列并且你想删除它会很好。 在我的例子中,第二行确实有更多的列,我希望这些列被集成并且列数 = MAX(列)。

            请参考下面我无法阅读的解决方案:

            try:
                df_data = pd.read_csv(PATH, header = bl_header, sep = str_sep)
            except pd.errors.ParserError as err:
                str_find = 'saw '
                int_position = int(str(err).find(str_find)) + len(str_find)
                str_nbCol = str(err)[int_position:]
                l_col = range(int(str_nbCol))
                df_data = pd.read_csv(PATH, header = bl_header, sep = str_sep, names = l_col)
            

            【讨论】:

            • 我会采取比我刚刚做的更好的方法来查找错误消息中的列数
            【解决方案9】:

            在我的例子中,分隔符不是默认的“,”而是制表符。

            pd.read_csv(file_name.csv, sep='\\t',lineterminator='\\r', engine='python', header='infer')
            

            注意:“\t”没有按照某些来源的建议工作。 "\\t" 是必需的。

            【讨论】:

              【解决方案10】:

              标记数据时出错。 C 错误:预计第 3 行中有 2 个字段,看到 12

              该错误为解决“Expected 2 fields in line 3, saw 12”问题提供了线索,saw 12 表示第二行的长度为 12,第一行的长度为 2。

              当您有如下所示的数据时,如果您跳过行,那么大部分数据将被跳过

              data = """1,2,3
              1,2,3,4
              1,2,3,4,5
              1,2
              1,2,3,4"""
              

              如果您不想跳过任何行,请执行以下操作

              #First lets find the maximum column for all the rows
              with open("file_name.csv", 'r') as temp_f:
                  # get No of columns in each line
                  col_count = [ len(l.split(",")) for l in temp_f.readlines() ]
              
              ### Generate column names  (names will be 0, 1, 2, ..., maximum columns - 1)
              column_names = [i for i in range(max(col_count))] 
              
              import pandas as pd
              # inside range set the maximum value you can see in "Expected 4 fields in line 2, saw 8"
              # here will be 8 
              data = pd.read_csv("file_name.csv",header = None,names=column_names )
              

              使用范围而不是手动设置名称,因为当您有很多列时会很麻烦。

              此外,如果您需要使用偶数数据长度,您可以用 0 填充 NaN 值。例如。用于聚类(k-means)

              new_data = data.fillna(0)
              

              【讨论】:

                【解决方案11】:

                在我的情况下,是因为csv文件的首尾两行的格式与文件中间的内容不同。

                所以我所做的就是将 csv 文件作为字符串打开,解析字符串的内容,然后使用read_csv 获取数据帧。

                import io
                import pandas as pd
                
                file = open(f'{file_path}/{file_name}', 'r')
                content = file.read()
                
                # change new line character from '\r\n' to '\n'
                lines = content.replace('\r', '').split('\n')
                
                # Remove the first and last 2 lines of the file
                # StringIO can be considered as a file stored in memory
                df = pd.read_csv(StringIO("\n".join(lines[2:-2])), header=None)
                

                【讨论】:

                  【解决方案12】:

                  据我所知,在查看您的文件后,问题在于您尝试加载的 csv 文件有多个表。有空行或包含表格标题的行。试着看看这个Stackoverflow answer。它展示了如何以编程方式实现这一目标。

                  另一种动态方法是使用csv module,一次读取每一行并进行完整性检查/正则表达式,以推断该行是否为(标题/标题/值/空白)。这种方法还有一个优势,您可以根据需要在 python 对象中拆分/追加/收集数据。

                  最简单的方法是在手动选择表格并将其复制到剪贴板后使用pandas函数pd.read_clipboard(),以防您可以在excel中打开csv或其他东西。

                  无关

                  另外,与您的问题无关,但因为没有人提到这一点:我在从 UCI 加载一些数据集(例如 seeds_dataset.txt)时遇到了同样的问题。就我而言,发生错误是因为某些分隔符的空格比真正的制表符\t 更多。例如,请参见下面的第 3 行

                  14.38   14.21   0.8951  5.386   3.312   2.462   4.956   1
                  14.69   14.49   0.8799  5.563   3.259   3.586   5.219   1
                  14.11   14.1    0.8911  5.42    3.302   2.7     5       1
                  

                  因此,在分隔符模式中使用\t+ 而不是\t

                  data = pd.read_csv(path, sep='\t+`, header=None)
                  

                  【讨论】:

                  • 谢谢,delimiter="\t+" 为我解决了错误!
                  【解决方案13】:

                  我遇到了这个带有杂散引号的错误。我使用映射软件,它会在导出以逗号分隔的文件时在文本项周围加上引号。使用引号(例如 ' = 英尺和 " = 英寸)的文本在引发分隔符冲突时可能会出现问题。考虑这个示例,它指出 5 英寸的测井打印效果不佳:

                  UWI_key,Latitude,Longitude,Remark US42051316890000,30.4386484,-96.4330734,"poor 5""

                  使用5" 作为5 inch 的简写最终会在工作中发挥作用。 Excel 会简单地去掉多余的引号,但 Pandas 在没有上面提到的 error_bad_lines=False 参数的情况下会崩溃。

                  【讨论】:

                    【解决方案14】:

                    对于那些在 Linux 操作系统上遇到 Python 3 类似问题的人。

                    pandas.errors.ParserError: Error tokenizing data. C error: Calling
                    read(nbytes) on source failed. Try engine='python'.
                    

                    试试:

                    df.read_csv('file.csv', encoding='utf8', engine='python')
                    

                    【讨论】:

                    • 我有一个文件,其中某些字段/列中有逗号,并且在尝试通过 pandas read_csv() 读取时失败,但在 read_csv() 中指定 engine="python" 作为参数有效 - 谢谢!
                    【解决方案15】:

                    简单解析:用excel打开csv文件,用csv格式的不同名称文件保存。再次尝试导入spyder,你的问题就解决了!

                    【讨论】:

                    • 老兄!谢谢你。您的解决方案就像一个电灯开关。
                    【解决方案16】:

                    以下内容对我有用(我发布了这个答案,因为我在 Google Colaboratory Notebook 中特别遇到了这个问题):

                    df = pd.read_csv("/path/foo.csv", delimiter=';', skiprows=0, low_memory=False)
                    

                    【讨论】:

                    • 我在没有将| 设置为我的 .csv 的分隔符时尝试了一些问题。我宁愿先尝试这种方法,而不是跳行或坏行。
                    • 我也遇到了同样的问题,我假设默认情况下会检测到“\t”作为分隔符。当我将分隔符明确设置为“\t”时,它起作用了。
                    • 对于一个大的 .csv 文件(~250MB),我遇到了同样的问题,其中一些损坏的行跨越的列比数据框实际拥有的列少。我能够通过两种方式避免异常:1)通过修改(例如删除)远离导致异常的行的几行 unrelated 行。 2) 通过设置low_memory=False。在其他具有相同类型的错误格式行的 .csv 文件中,我没有发现任何问题。总之,这表明pandas.read_csv()对大文件的处理存在某种缺陷。
                    • 我提交了与我之前的评论相关的bug report
                    【解决方案17】:

                    我使用的数据集有很多引号 (") 与格式无关。我能够通过为 read_csv() 包含此参数来修复错误:

                    quoting=3 # 3 correlates to csv.QUOTE_NONE for pandas
                    

                    【讨论】:

                    • 偶然发现了完全相同的东西。就我而言,这是正确的答案。接受的只是隐藏错误。
                    • 对我来说也是正确的答案。 +1
                    【解决方案18】:

                    大部分有用的答案都已提及,但我建议将 pandas 数据帧保存为 parquet 文件。 Parquet 文件没有这个问题,而且它们同时具有内存效率。

                    【讨论】:

                    • 我同意这个答案。将 Pandas DataFrame 编写为 parquet 文件解决了我的相关问题。
                    【解决方案19】:

                    我遇到了这个带有杂散引号的错误。我使用映射软件,它会在导出以逗号分隔的文件时在文本项周围加上引号。使用引号(例如 ' = 英尺和 " = 英寸)的文本可能会出现问题。考虑这个例子,它指出 5 英寸的测井打印效果不佳:

                    UWI_key,Latitude,Longitude,Remark US42051316890000,30.4386484,-96.4330734,"poor 5""

                    使用5" 作为5 inch 的简写最终会在工作中发挥作用。 Excel 会简单地去掉多余的引号,但 Pandas 在没有上面提到的 error_bad_lines=False 参数的情况下会崩溃。

                    一旦您知道错误的性质,在导入之前从文本编辑器(例如,Sublime Text 3 或 Notepad++)进行查找替换可能是最简单的。

                    【讨论】:

                      【解决方案20】:

                      对我来说,问题是在我的 CSVintraday 中附加了一个新列。如果我使用error_bad_lines=False,则接受的答案解决方案将不起作用,因为每个未来的行都将被丢弃。

                      这种情况下的解决方案是在pd.read_csv() 中使用usecols 参数。这样,我可以只指定我需要读入 CSV 的列,并且我的 Python 代码将保持对未来 CSV 更改的弹性,只要标题列存在(并且列名不会更改)。

                      usecols : list-like or callable, optional 
                      
                      Return a subset of the columns. If list-like, all elements must either
                      be positional (i.e. integer indices into the document columns) or
                      strings that correspond to column names provided either by the user in
                      names or inferred from the document header row(s). For example, a
                      valid list-like usecols parameter would be [0, 1, 2] or ['foo', 'bar',
                      'baz']. Element order is ignored, so usecols=[0, 1] is the same as [1,
                      0]. To instantiate a DataFrame from data with element order preserved
                      use pd.read_csv(data, usecols=['foo', 'bar'])[['foo', 'bar']] for
                      columns in ['foo', 'bar'] order or pd.read_csv(data, usecols=['foo',
                      'bar'])[['bar', 'foo']] for ['bar', 'foo'] order.
                      

                      示例

                      my_columns = ['foo', 'bar', 'bob']
                      df = pd.read_csv(file_path, usecols=my_columns)
                      

                      这样做的另一个好处是,如果我只使用具有 18-20 列的 CSV 的 3-4 列,我可以将更少的数据加载到内存中。

                      【讨论】:

                        【解决方案21】:

                        我遇到了这个问题,我试图在没有传入列名的情况下读取 CSV。

                        df = pd.read_csv(filename, header=None)
                        

                        我事先在列表中指定了列名,然后将它们传递给names,它立即解决了它。如果您没有设置列名,则可以创建与数据中可能包含的最大列数一样多的占位符名称。

                        col_names = ["col1", "col2", "col3", ...]
                        df = pd.read_csv(filename, names=col_names)
                        

                        【讨论】:

                        • 这个答案更好,因为与使用 error_bad_line=False 相比,该行不会被删除。此外,一旦使用此解决方案制作数据框,您就可以轻松找出哪些行是有问题的行。
                        • 我同意@zipline86。这个答案既安全又智能。
                        • 这个解决方案对我来说太老套了,但它确实有效。我解决了在 read_csv 中传递 engine='python' 以处理可变列大小的问题
                        【解决方案22】:

                        read_csv 时我遇到了同样的问题:ParserError: Error tokenizing data。 我刚刚将旧的 csv 文件保存到一个新的 csv 文件中。问题解决了!

                        【讨论】:

                          【解决方案23】:

                          在参数中使用分隔符

                          pd.read_csv(filename, delimiter=",", encoding='utf-8')
                          

                          它会读取。

                          【讨论】:

                            【解决方案24】:

                            我有类似的情况和设置

                            train = pd.read_csv('input.csv' , encoding='latin1',engine='python') 
                            

                            工作

                            【讨论】:

                              【解决方案25】:

                              问题可能与文件问题有关,就我而言,重命名文件后问题已解决。还没弄清楚原因..

                              【讨论】:

                                【解决方案26】:

                                这就是我所做的。

                                sep='::' 解决了我的问题:

                                data=pd.read_csv('C:\\Users\\HP\\Downloads\\NPL ASSINGMENT 2 imdb_labelled\\imdb_labelled.txt',engine='python',header=None,sep='::')
                                

                                【讨论】:

                                  【解决方案27】:

                                  你可以做这一步来避免这个问题 -

                                  train = pd.read_csv('/home/Project/output.csv' , header=None)
                                  

                                  只需添加 - header=None

                                  希望这会有所帮助!

                                  【讨论】:

                                    【解决方案28】:

                                    我从同事那里收到了一个 .csv,当我尝试使用 pd.read_csv() 读取 csv 时,我收到了类似的错误。它显然是在尝试使用第一行来生成数据框的列,但是有很多行包含的列比第一行所暗示的要多。我最终解决了这个问题,只需打开文件并将其重新保存为 .csv 并再次使用 pd.read_csv()。

                                    【讨论】:

                                      【解决方案29】:

                                      以下命令序列有效(我丢失了数据的第一行 -no header=None present-,但至少它加载了):

                                      df = pd.read_csv(filename, usecols=range(0, 42)) df.columns = ['YR', 'MO', 'DAY', 'HR', 'MIN', 'SEC', 'HUND', 'ERROR', 'RECTYPE', 'LANE', 'SPEED', 'CLASS', 'LENGTH', 'GVW', 'ESAL', 'W1', 'S1', 'W2', 'S2', 'W3', 'S3', 'W4', 'S4', 'W5', 'S5', 'W6', 'S6', 'W7', 'S7', 'W8', 'S8', 'W9', 'S9', 'W10', 'S10', 'W11', 'S11', 'W12', 'S12', 'W13', 'S13', 'W14']

                                      以下不起作用:

                                      df = pd.read_csv(filename, names=['YR', 'MO', 'DAY', 'HR', 'MIN', 'SEC', 'HUND', 'ERROR', 'RECTYPE', 'LANE', 'SPEED', 'CLASS', 'LENGTH', 'GVW', 'ESAL', 'W1', 'S1', 'W2', 'S2', 'W3', 'S3', 'W4', 'S4', 'W5', 'S5', 'W6', 'S6', 'W7', 'S7', 'W8', 'S8', 'W9', 'S9', 'W10', 'S10', 'W11', 'S11', 'W12', 'S12', 'W13', 'S13', 'W14'], usecols=range(0, 42))

                                      CParserError:标记数据时出错。 C 错误:预计第 1605634 行中有 53 个字段,看到 54 以下不起作用:

                                      df = pd.read_csv(filename, header=None)

                                      CParserError:标记数据时出错。 C 错误:预计第 1605634 行中有 53 个字段,看到 54

                                      因此,在您的问题中,您必须通过 usecols=range(0, 2)

                                      【讨论】:

                                        【解决方案30】:

                                        我发现在处理类似的解析错误时有用的替代方法是使用 CSV 模块将数据重新路由到 pandas df。例如:

                                        import csv
                                        import pandas as pd
                                        path = 'C:/FileLocation/'
                                        file = 'filename.csv'
                                        f = open(path+file,'rt')
                                        reader = csv.reader(f)
                                        
                                        #once contents are available, I then put them in a list
                                        csv_list = []
                                        for l in reader:
                                            csv_list.append(l)
                                        f.close()
                                        #now pandas has no problem getting into a df
                                        df = pd.DataFrame(csv_list)
                                        

                                        我发现 CSV 模块对于格式不佳的逗号分隔文件更加健壮,因此通过这种方式成功解决了此类问题。

                                        【讨论】:

                                          猜你喜欢
                                          • 2016-08-23
                                          • 1970-01-01
                                          • 1970-01-01
                                          • 2019-08-06
                                          • 1970-01-01
                                          • 1970-01-01
                                          • 2020-02-03
                                          相关资源
                                          最近更新 更多