【问题标题】:Pandas, read CSV ignoring extra commas熊猫,阅读 CSV 忽略额外的逗号
【发布时间】:2018-07-17 23:57:25
【问题描述】:

我正在将一个包含 8 列的 CSV 文件读取到 Pandas 数据框中。最后一列包含一条错误消息,其中一些包含逗号。这会导致文件读取失败并出现错误ParserError: Error tokenizing data. C error: Expected 8 fields in line 21922, saw 9

有没有办法忽略第 8 个字段之后的所有逗号,而不必遍历文件并删除多余的逗号?

读取文件的代码:

import pandas as pd
df = pd.read_csv('C:\\somepath\\output.csv')

行之有效:

061AE,Active,001,2017_02_24 15_18_01,00006,1,00013,some message

失败的行:

061AE,Active,001,2017_02_24 15_18_01,00006,1,00013,longer message, with commas

【问题讨论】:

  • 更新了代码和数据格式。
  • pandas #2886。这是一个尚未解决的问题。不幸的是,我认为没有办法绕过预处理。
  • 原始数据是从 XML 文件中解析出来的。您认为将每一列放在“引号”中会起作用吗?
  • @MikeS159 引号无济于事,但如果在解析过程中您可以在单元格之间使用制表符或分号分隔符,那么您可以毫无问题地使用简单的pd.read_csv('filename')。与以后必须处理它相比,这实际上是理想的。

标签: python pandas


【解决方案1】:

加入@Tblaz 回答如果您使用GoogleColab,您可以使用此解决方案,在我的情况下,额外的逗号位于第 24 列,因此我只需阅读 23 列:

import pandas as pd
from google.colab import files
import io
uploaded = files.upload()
x_train = pd.read_csv(io.StringIO(uploaded['x_train.csv'].decode('utf-8')), skiprows=1, usecols=range(23) ,header=None)

【讨论】:

    【解决方案2】:

    您可以在Pandas issues page 上发布的这个环形交叉路口拍照:

    import csv
    import pandas as pd
    import numpy as np
    
    df = pd.read_csv('filename.csv', parse_dates=True, dtype=Object, delimiter="\t", quoting=csv.QUOTE_NONE, encoding='utf-8')
    

    您还可以对数据进行预处理,基本上将所有前 7 个(第 0 到第 6 个,包括第 0 到第 6 个)逗号更改为分号,并将之后的逗号保留为逗号*,使用以下内容:

    to_write = []
    counter = 0
    with open("sampleCSV.csv", "r") as f:
        for line in f:
            while counter < 7:
                line = list(line)
                line[line.index(",")] = ";"
                counter += 1
            counter = 0
            to_write.append("".join(line))
    

    您现在可以将此 to_write 列表作为 Pandas 对象阅读,例如

    data = pd.DataFrame(to_write)
    data = pd.DataFrame(data[0].str.split(";").values.tolist()),
    

    或将其写回 csv 并使用带有分号分隔符的 pandas 读取,例如 read_csv(csv_path, sep=';')

    我在没有经过严格测试的情况下快速起草了这份文件,但应该会给你一些尝试的想法。如果有帮助或没有帮助,请发表评论,我会编辑它。

    *另一种选择是删除 7 号之后的所有逗号,并继续使用逗号分隔符。无论哪种方式,重点是区分前 7 个分隔符和后续标点符号。

    【讨论】:

      【解决方案3】:

      您可以使用re.sub 将前几个逗号替换为“|”,将中间结果保存在StringIO 中,然后进行处理。

      import pandas as pd
      from io import StringIO
      import re
      
      for_pd = StringIO()
      with open('MikeS159.csv') as mike:
          for line in mike:
              new_line = re.sub(r',', '|', line.rstrip(), count=7)
              print (new_line, file=for_pd)
      
      for_pd.seek(0)
      
      df = pd.read_csv(for_pd, sep='|', header=None)
      print (df)
      

      我将您问题中的两行放入一个文件中以获取此输出。

             0       1  2                    3  4  5   6  \
      0  061AE  Active  1  2017_02_24 15_18_01  6  1  13   
      1  061AE  Active  1  2017_02_24 15_18_01  6  1  13   
      
                                   7  
      0                 some message  
      1  longer message, with commas  
      

      【讨论】:

      • 这太整洁了! StringIOre 技巧都非常好。谢谢!
      • @MikeS159:祝你好运!
      • 不客气。但是你不应该写“它起作用了”,好像它是一个惊喜。 :-)
      • 有没有办法替换一定数量列中的所有逗号?在我的案例中,我有 6 列,第 2-6 列中有 14-15 个逗号。我现在将计数设置为 15。我认为这也可以,但也许有更优雅的解决方案?
      • @Tobitor:说实话,我最近没有做太多工作(我已经退休了)。您最好将此作为问题发布以获取最新想法。
      【解决方案4】:

      您可以使用read_csv函数中的参数usecols来限制您读取的列。例如:

      import pandas as pd
      pd.read_csv(path, usecols=range(8))
      

      如果您只想阅读前 8 列。

      【讨论】:

      • 那会截断消息吗?我已经用一个示例更新了我的问题,但基本上某些消息列包含带有逗号的文本。我想阅读整条消息并忽略该逗号作为分隔符。
      • 这只会读入 CSV 文件的第 0-7 列,如果长文本是第 8 列,则不会读入。我想我误解了你的问题!
      猜你喜欢
      • 2019-11-30
      • 2015-12-21
      • 2020-10-01
      • 1970-01-01
      • 2021-02-13
      • 2018-02-15
      • 1970-01-01
      • 2012-05-16
      • 2015-05-09
      相关资源
      最近更新 更多