【问题标题】:Pandas read csv with formatting errorsPandas 读取 csv 格式错误
【发布时间】:2021-08-27 21:30:59
【问题描述】:

我需要加载一个 csv 文件,其中空格用作制表符,如下所示:

2021-08-27 12:21:28.259 2021-08-25 17:36:52.045 1,9253 -2,0298 -1,3901 356,6895 111,0229 893,0664 -162,1033 -35,9802 131,6052

但是有些行格式错误,值太大,并且某些值之间没有空格

2021-08-27 12:21:28.350 2021-08-25 17:36:52.155 -4,7617 -5,2017 -8,0220 -1484,8022 -127,9907-1999,7559 99,7943 -55,4700 -109,0063

因此,当我使用 pd.read_csv() 导入 csv 时,我会得到一些带有移位值的行。

我尝试逐行编辑文本文件,在 - 之前添加空格,但处理时间太长。

有没有一种在加载时编辑 csv 的快速方法?

好东西是每列总是在固定位置开始(和结束),但我没有找到任何方法在知道列开始/的熊猫中加载 csv结束索引

【问题讨论】:

  • 如果这不是一个非常大的文件,我建议您使用 python 脚本仅使用字符串来拆分数据。那会更容易。但如果它是一个非常大的文件,那么这不是一个选项
  • 你不能只改变csv中空格的大小吗? `
  • @Tharaka Devinda:是的,这是一个大文件。我已经试过了,时间太长了
  • @Julien 问题不在于空格的大小,而在于它们不存在
  • 你总是有 4 位小数吗?如果是,我可以制定一些正则表达式来执行替换。你也可以看看read_fwfpanda 的函数 for fixed-width-format

标签: python pandas csv


【解决方案1】:

更新:

像这样使用read_fwf

pandas.read_fwf('test.csv', header=None)

可能有效,但不适用于问题中提供的文件示例。

我们可以通过提供如下字段的位置来帮助 python

colspecs = [(0, 10), (11, 23), (24, 34), (35, 47), (48, 58), (58, 68), (68, 78), (78, 89), (89, 99), (99, 109), (109, 120), (120, 130), (130, 140)]
pandas.read_fwf('test.csv', infer_nrows = 13, header=None, colspecs = colspecs)

文档链接:https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.read_fwf.html

【讨论】:

  • 太棒了!不知道这个。最好在您的答案中包含文档链接:pandas.pydata.org/docs/reference/api/…
  • 当我仅使用 OP 的示例两行尝试它时,即使指定 infer_nrows=13,它也无法将 -127,9907-1999,7559 分成两列。如果至少有一个行更好地分开,希望它能在更大的数据集上成功。否则,我们仍然可以使用widths 可选参数手动指定拆分列的位置。
  • 你是对的@Stef,我正在努力 colspecs 提供正确的答案。
  • 如果您相信我的计数:[0, 11, 24, 35, 48, 58, 68, 78, 89, 99, 109, 120, 130, 140](这是itertools.accumulate 在我的答案中使用的宽度的结果)
  • 我不会说“像这样使用read_fwf [...] 将不起作用”。它很可能适用于更大的数据集,其中前 100 行中至少有一个可以帮助分离两个烦人的列。但是我们只有两行来测试它,它们对于 pandas 来说是不够的。当它确实起作用时,最好让read_fwf 推断列,而不是硬编码它们。
【解决方案2】:

这个答案描述了如何手动解析文件。一个更好的解决方案是改用pandas.read_fwf

由于所有列的大小相同,您可以使用列表推导来拆分列:

# data.csv
2021-08-27 12:21:28.350 2021-08-25 17:36:52.155    -4,7617   -5,2017   -8,0220 -1484,8022 -127,9907-1999,7559    99,7943  -55,4700 -109,0063
2021-08-27 12:21:28.259 2021-08-25 17:36:52.045     1,9253   -2,0298   -1,3901   356,6895  111,0229  893,0664  -162,1033  -35,9802  131,6052
import itertools # accumulate

def load_file(filename, widths):
  with open(filename, 'r') as f:
    table = []
    for line in f:
      table.append([line[p:p+w] for w,p in zip(widths, itertools.accumulate(widths, initial=0))])
  return table

print(load_file('data.csv', [11,13,11,13,10,10,10,11,10,10,11,10,10]))
# [['2021-08-27 ', '12:21:28.350 ', '2021-08-25 ', '17:36:52.155 ', '   -4,7617', '   -5,2017', '   -8,0220', ' -1484,8022', ' -127,9907', '-1999,7559', '    99,7943', '  -55,4700', ' -109,0063'],
#  ['2021-08-27 ', '12:21:28.259 ', '2021-08-25 ', '17:36:52.045 ', '    1,9253', '   -2,0298', '   -1,3901', '   356,6895', '  111,0229', '  893,0664', '  -162,1033', '  -35,9802', '  131,6052']]

然后你可以直接将结果表加载到pandas中,希望它能正确解析所有的数字和日期;或者如果您尝试更手动地解析值,那么.strip() 将有助于删除所有尾随空格。

【讨论】:

  • 此解决方案是否会减慢处理时间?
  • @Ohibò 你告诉我。我在您提供的数据上进行了尝试,它只有两行。在越来越大的数据上尝试一下,您可以告诉我们结果如何。
猜你喜欢
  • 1970-01-01
  • 2019-02-17
  • 2022-11-03
  • 1970-01-01
  • 2023-02-20
  • 2019-07-16
  • 2017-12-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多