【问题标题】:Read CSV into a dataFrame with varying row lengths using Pandas使用 Pandas 将 CSV 读入具有不同行长的数据帧
【发布时间】:2019-08-03 09:46:12
【问题描述】:

所以我有一个看起来有点像这样的 CSV:

1 | 01-01-2019 | 724
2 | 01-01-2019 | 233 | 436
3 | 01-01-2019 | 345
4 | 01-01-2019 | 803 | 933 | 943 | 923 | 954
5 | 01-01-2019 | 454
...

当我尝试使用以下代码生成数据帧时..

df = pd.read_csv('data.csv', header=0, engine='c', error_bad_lines=False)

它只将 3 列的行添加到 df(上面的第 1、3 和 5 行)

其余的被认为是“坏行”,给我以下错误:

Skipping line 17467: expected 3 fields, saw 9

如何在我的 csv 中创建一个包含 所有 数据的数据框,可能只是用 null 填充空单元格?还是我必须在添加到 df 之前声明最大行长度?

谢谢!

【问题讨论】:

  • 您将需要低于最大长度的行才能有空列,因此在普通的csv 中类似于a,b,c,,,,

标签: python pandas csv dataframe


【解决方案1】:

如果您知道数据包含N 列,您可以 通过names 参数提前告诉 Pandas 需要多少列:

import pandas as pd
df = pd.read_csv('data', delimiter='|', names=list(range(7)))
print(df)

产量

   0             1    2      3      4      5      6
0  1   01-01-2019   724    NaN    NaN    NaN    NaN
1  2   01-01-2019   233  436.0    NaN    NaN    NaN
2  3   01-01-2019   345    NaN    NaN    NaN    NaN
3  4   01-01-2019   803  933.0  943.0  923.0  954.0
4  5   01-01-2019   454    NaN    NaN    NaN    NaN

如果您对列数有上限N,那么您可以 让 Pandas 读取 N 列,然后使用 dropna 删除完全空的列:

import pandas as pd
df = pd.read_csv('data', delimiter='|', names=list(range(20))).dropna(axis='columns', how='all')
print(df)

产量

   0             1    2      3      4      5      6
0  1   01-01-2019   724    NaN    NaN    NaN    NaN
1  2   01-01-2019   233  436.0    NaN    NaN    NaN
2  3   01-01-2019   345    NaN    NaN    NaN    NaN
3  4   01-01-2019   803  933.0  943.0  923.0  954.0
4  5   01-01-2019   454    NaN    NaN    NaN    NaN

请注意,这可能会从数据集的中间删除列(不仅仅是 右侧的列)如果它们完全为空。

【讨论】:

  • 由于某种原因,其他解决方案对我不起作用,但添加 names 参数就可以了,干杯!
  • 添加名称对我有用,因为我在大型 csv 中有不规则的列。谢谢!
【解决方案2】:
colnames= [str(i) for i in range(9)]
df = pd.read_table('data.csv', header=None, sep=',', names=colnames)

如果代码出现错误,请将列名中的 9 更改为数字 x

Skipping line 17467: expected 3 fields, saw x

【讨论】:

    【解决方案3】:

    考虑使用 Python csv 来完成导入数据和格式修饰的提升。您可以实现自定义方言来处理不同的 csv-ness。

    import csv
    import pandas as pd
    
    csv_data = """1 | 01-01-2019 | 724
    2 | 01-01-2019 | 233 | 436
    3 | 01-01-2019 | 345
    4 | 01-01-2019 | 803 | 933 | 943 | 923 | 954
    5 | 01-01-2019 | 454"""
    
    with open('test1.csv', 'w') as f:
        f.write(csv_data)
    
    csv.register_dialect('PipeDialect', delimiter='|')
    with open('test1.csv') as csvfile:
        data = [row for row in csv.reader(csvfile, 'PipeDialect')]
    df = pd.DataFrame(data = data)
    

    为您提供 csv 导入方言和以下 DataFrame:

        0             1      2      3      4      5     6
    0  1    01-01-2019     724   None   None   None  None
    1  2    01-01-2019    233     436   None   None  None
    2  3    01-01-2019     345   None   None   None  None
    3  4    01-01-2019    803    933    943    923    954
    4  5    01-01-2019     454   None   None   None  None
    

    剩下的练习是处理输入文件中的空白填充。

    【讨论】:

    • 自我说明:pandas.read_csv(engine=) 将使用 python 的 csv 模块(如果指定)。
    【解决方案4】:

    读取固定宽度应该可以工作:

    from io import StringIO
    
    s = '''1  01-01-2019  724
    2  01-01-2019  233  436
    3  01-01-2019  345
    4  01-01-2019  803  933  943  923  954
    5  01-01-2019  454'''
    
    
    pd.read_fwf(StringIO(s), header=None)
    
       0           1    2      3      4      5      6
    0  1  01-01-2019  724    NaN    NaN    NaN    NaN
    1  2  01-01-2019  233  436.0    NaN    NaN    NaN
    2  3  01-01-2019  345    NaN    NaN    NaN    NaN
    3  4  01-01-2019  803  933.0  943.0  923.0  954.0
    4  5  01-01-2019  454    NaN    NaN    NaN    NaN
    

    或使用delimiter 参数

    s = '''1 | 01-01-2019 | 724
    2 | 01-01-2019 | 233 | 436
    3 | 01-01-2019 | 345
    4 | 01-01-2019 | 803 | 933 | 943 | 923 | 954
    5 | 01-01-2019 | 454'''
    
    
    pd.read_fwf(StringIO(s), header=None, delimiter='|')
    
       0             1    2      3      4      5      6
    0  1   01-01-2019   724    NaN    NaN    NaN    NaN
    1  2   01-01-2019   233  436.0    NaN    NaN    NaN
    2  3   01-01-2019   345    NaN    NaN    NaN    NaN
    3  4   01-01-2019   803  933.0  943.0  923.0  954.0
    4  5   01-01-2019   454    NaN    NaN    NaN    NaN
    

    请注意,对于您的实际文件,您不会使用StringIO,您只需将其替换为您的文件路径:pd.read_fwf('data.csv', delimiter='|', header=None)

    【讨论】:

      【解决方案5】:

      在 csv 文件的顶部添加额外的列(空的或其他的)。 Pandas 将第一行作为默认大小,低于它的任何内容都将具有 NaN 值。示例:

      文件.csv:

      a,b,c,d,e
      1,2,3
      3
      2,3,4
      

      代码:

      >>> import pandas as pd
      >>> pd.read_csv('file.csv')
         a    b    c   d   e
      0  1  2.0  3.0 NaN NaN
      1  3  NaN  NaN NaN NaN
      2  2  3.0  4.0 NaN NaN
      

      【讨论】:

        【解决方案6】:

        如果只使用pandas,读入行,处理后面的分隔符。

        import pandas as pd
        
        df = pd.read_csv('data.csv', header=None, sep='\n')
        df = df[0].str.split('\s\|\s', expand=True)
        
           0           1    2     3     4     5     6
        0  1  01-01-2019  724  None  None  None  None
        1  2  01-01-2019  233   436  None  None  None
        2  3  01-01-2019  345  None  None  None  None
        3  4  01-01-2019  803   933   943   923   954
        4  5  01-01-2019  454  None  None  None  None
        

        【讨论】:

        • 非常紧凑!是否有一种简单的方法来处理包含分隔符的文本行?我认为逗号作为分隔符和包含逗号的文本,或者在 OP 的情况下类似于 2 | 01-01-2019 | "Two | | lines" | 123 | text
        猜你喜欢
        • 2021-12-27
        • 2019-01-29
        • 1970-01-01
        • 2017-08-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多