【问题标题】:ParserError with panda read_csv熊猫 read_csv 的 ParserError
【发布时间】:2018-01-27 13:57:46
【问题描述】:

我正在尝试读取每行列数不同的 txt 文件。这是我文件的开头:

60381 6
1 0.270 0.30 0.30 0.70 0.70
4.988 4.988 4.988 4.988 4.988 4.988 4.988 4.988 4.988 4.988 4.988 4.988
2 0.078 0.30 0.30 0.70 0.70
5.387 5.312 5.338 4.463 4.675 4.275 4.238 3.562 3.175 3.925 4.950 4.762
6 0.241 0.30 0.60 0.70 0.40
3.700 3.200 2.738 2.325 1.250 0.975 1.175 1.950 2.488 3.613 3.987 3.950
7 0.357 0.30 0.60 0.70 0.40
1.212 1.125 1.050 0.950 0.663 0.488 0.425 0.512 0.637 0.900 1.112 1.188
8 0.031 0.30 0.70 0.70 0.30
0.225 0.213 0.200 0.175 0.200 0.213 0.375 0.887 0.975 0.512 0.262 0.262
10 0.022 0.30 0.80 0.70 0.20
0.712 0.700 0.738 0.550 0.513 0.688 0.613 0.600 0.850 0.812 0.800 0.775
60382 5
6 0.197 0.30 0.60 0.70 0.40
3.700 3.200 2.738 2.325 1.250 0.975 1.175 1.950 2.488 3.613 3.987 3.950
7 0.413 0.30 0.60 0.70 0.40
1.212 1.125 1.050 0.950 0.663 0.488 0.425 0.512 0.637 0.900 1.112 1.188
8 0.016 0.30 0.70 0.70 0.30
0.225 0.213 0.200 0.175 0.200 0.213 0.375 0.887 0.975 0.512 0.262 0.262
10 0.111 0.30 0.80 0.70 0.20
0.712 0.700 0.738 0.550 0.513 0.688 0.613 0.600 0.850 0.812 0.800 0.775
11 0.263 0.30 0.50 0.70 0.50
1.812 1.388 1.087 0.825 0.538 0.400 0.338 0.400 0.500 0.925 0.962 1.100

我尝试使用 pandas read_csv 来阅读它:

import pandas as pd
data = pd.read_csv('./myfile.txt',header=None,sep='\s')

这给出了以下错误:

ParserError: Expected 6 fields in line 3, saw 12. Error could possibly be due to quotes being ignored when a multi-char delimiter is used.

所以我的文件没有多字符分隔符或引号。我已经尝试过在这个论坛上找到的解决方案,建议使用:

data = pd.read_csv(open('./myfile.txt','r'), header=None,encoding='utf-8', engine='c')

虽然这样解决了上面的错误,但是我看到的数组没有使用空格作为列的分隔符,输出只有1列:

我应该如何读取文件以获取每个值的列?我不介意是否有 nan 值填充其余部分。

【问题讨论】:

  • "the array I'm presented with does not use space as a delimiter of columns" 为什么会这样?您从未告诉read_csv 该文件使用空格作为分隔符。您需要将delimiter=' ' 传递给read_csv
  • 包含两个元素的行(例如60381 6)对我来说似乎是元数据。你确定这是一个标准的 csv 文件吗?
  • 同意@ayhan - 这就是它的原因
  • @DeepSpace 好吧,我不想让帖子太长。我确实尝试在最后添加分隔符sep=\s,但我得到了另一个错误:ValueError: the 'c' engine does not support regex separators (separators > 1 char and different from '\s+' is Explained as regex )。使用 sep=\s+' and/or removing the engine = 'c'` 再次给出 ParserError。
  • @ayhan 原始文件是 *.txt,看起来和我分享的完全一样。我尝试使用 read_csv 因为我看到人们在处理每行具有不同列数的文件时倾向于建议使用它。关于如何解决问题的任何建议?

标签: python python-3.x pandas csv


【解决方案1】:

如果您设法在单个列中获取数据,则可以使用Series.str.split() 来解决此问题。

以下是您提供的一些示例数据的示例(您可以使用任何字符串或正则表达式作为split() 中的分隔符):

df[0].str.split(' ', expand=True)

     0      1      2      3      4      5      6      7      8      9   \
0  0.270   0.30   0.30   0.70   0.70   None   None   None   None   None
1  4.988  4.988  4.988  4.988  4.988  4.988  4.988  4.988  4.988  4.988

如果您这样做,那么您不妨使用pd.DataFrame(open(...).readlines()) 或类似的东西创建数据框,因为您根本不会从read_csv() 中受益,而且您的文件也不完全是标准的 csv 文件。

# f is a StringIO with some of your sample data to simulate a file
df = pd.DataFrame(line.strip().split(' ') for line in f)

       0      1      2      3      4      5      6      7      8      9   \
0   60381      6   None   None   None   None   None   None   None   None
1       1  0.270   0.30   0.30   0.70   0.70   None   None   None   None
2   4.988  4.988  4.988  4.988  4.988  4.988  4.988  4.988  4.988  4.988
3       2  0.078   0.30   0.30   0.70   0.70   None   None   None   None
4   5.387  5.312  5.338  4.463  4.675  4.275  4.238  3.562  3.175  3.925

当然,您也可以通过确保每行包含相同数量的列来修复输入文件,这将解决ParserError 问题。

【讨论】:

    【解决方案2】:

    考虑迭代重建文本文件,然后pd.read_table() 清理文本版本:

    from io import StringIO
    
    txt="""
    60381 6
    1 0.270 0.30 0.30 0.70 0.70
    4.988 4.988 4.988 4.988 4.988 4.988 4.988 4.988 4.988 4.988 4.988 4.988
    2 0.078 0.30 0.30 0.70 0.70
    5.387 5.312 5.338 4.463 4.675 4.275 4.238 3.562 3.175 3.925 4.950 4.762
    6 0.241 0.30 0.60 0.70 0.40
    3.700 3.200 2.738 2.325 1.250 0.975 1.175 1.950 2.488 3.613 3.987 3.950
    7 0.357 0.30 0.60 0.70 0.40
    1.212 1.125 1.050 0.950 0.663 0.488 0.425 0.512 0.637 0.900 1.112 1.188
    8 0.031 0.30 0.70 0.70 0.30
    0.225 0.213 0.200 0.175 0.200 0.213 0.375 0.887 0.975 0.512 0.262 0.262
    10 0.022 0.30 0.80 0.70 0.20
    0.712 0.700 0.738 0.550 0.513 0.688 0.613 0.600 0.850 0.812 0.800 0.775
    60382 5
    6 0.197 0.30 0.60 0.70 0.40
    3.700 3.200 2.738 2.325 1.250 0.975 1.175 1.950 2.488 3.613 3.987 3.950
    7 0.413 0.30 0.60 0.70 0.40
    1.212 1.125 1.050 0.950 0.663 0.488 0.425 0.512 0.637 0.900 1.112 1.188
    8 0.016 0.30 0.70 0.70 0.30
    0.225 0.213 0.200 0.175 0.200 0.213 0.375 0.887 0.975 0.512 0.262 0.262
    10 0.111 0.30 0.80 0.70 0.20
    0.712 0.700 0.738 0.550 0.513 0.688 0.613 0.600 0.850 0.812 0.800 0.775
    11 0.263 0.30 0.50 0.70 0.50
    1.812 1.388 1.087 0.825 0.538 0.400 0.338 0.400 0.500 0.925 0.962 1.100
    """
    
    for line in StringIO(txt):
    
        if len(line) == 8:
            header = line
            next
        if len(line) == 28 or len(line) == 29:
            firstdata = line
            next
        if len(line) == 72:
            seconddata = header + ' ' + firstdata + ' ' + line
            print(seconddata.replace("\n", ""))
    

    输出

    # 60381 6 1 0.270 0.30 0.30 0.70 0.70 4.988 4.988 4.988 4.988 4.988 4.988 4.988 4.988 4.988 4.988 4.988 4.988
    # 60381 6 2 0.078 0.30 0.30 0.70 0.70 5.387 5.312 5.338 4.463 4.675 4.275 4.238 3.562 3.175 3.925 4.950 4.762
    # 60381 6 6 0.241 0.30 0.60 0.70 0.40 3.700 3.200 2.738 2.325 1.250 0.975 1.175 1.950 2.488 3.613 3.987 3.950
    # 60381 6 7 0.357 0.30 0.60 0.70 0.40 1.212 1.125 1.050 0.950 0.663 0.488 0.425 0.512 0.637 0.900 1.112 1.188
    # 60381 6 8 0.031 0.30 0.70 0.70 0.30 0.225 0.213 0.200 0.175 0.200 0.213 0.375 0.887 0.975 0.512 0.262 0.262
    # 60381 6 10 0.022 0.30 0.80 0.70 0.20 0.712 0.700 0.738 0.550 0.513 0.688 0.613 0.600 0.850 0.812 0.800 0.775
    # 60382 5 6 0.197 0.30 0.60 0.70 0.40 3.700 3.200 2.738 2.325 1.250 0.975 1.175 1.950 2.488 3.613 3.987 3.950
    # 60382 5 7 0.413 0.30 0.60 0.70 0.40 1.212 1.125 1.050 0.950 0.663 0.488 0.425 0.512 0.637 0.900 1.112 1.188
    # 60382 5 8 0.016 0.30 0.70 0.70 0.30 0.225 0.213 0.200 0.175 0.200 0.213 0.375 0.887 0.975 0.512 0.262 0.262
    # 60382 5 10 0.111 0.30 0.80 0.70 0.20 0.712 0.700 0.738 0.550 0.513 0.688 0.613 0.600 0.850 0.812 0.800 0.775
    # 60382 5 11 0.263 0.30 0.50 0.70 0.50 1.812 1.388 1.087 0.825 0.538 0.400 0.338 0.400 0.500 0.925 0.962 1.100
    

    现在将文件导入 pandas,考虑将新输出写入文本文件:

    with open('input.txt', 'r') as f1, open('output.txt', 'w') as f2:
       for line in f1:
          if len(line) == 8:
              header = line
              next
          if len(line) == 28 or len(line) == 29:
              firstdata = line
              next
          if len(line) == 72:
              seconddata = header + ' ' + firstdata + ' ' + line
              f2.write(seconddata.replace("\n", ""))
    
    df = read.table('output.txt', header=None, sep="\\s+")
    

    【讨论】:

    • 这会生成一个文件,每个值只有 1 行和 1 列。它还遗漏了一些数据,因为如果 firstadaseconddata ,并非所有标题的数量都相同。
    猜你喜欢
    • 2016-03-30
    • 2019-07-12
    • 2017-08-02
    • 1970-01-01
    • 2019-12-31
    • 2012-11-21
    • 2018-07-19
    • 2020-08-24
    • 1970-01-01
    相关资源
    最近更新 更多