【问题标题】:Pandas read multiindexed csv with blanksPandas 读取带有空格的多索引 csv
【发布时间】:2015-07-31 02:26:11
【问题描述】:

我正在努力正确加载一个带有空格的多行标题的 csv。 CSV 如下所示:

,,C,,,D,,
A,B,X,Y,Z,X,Y,Z
1,2,3,4,5,6,7,8

我想得到的是:

当我尝试使用 pd.read_csv(file, header=[0,1], sep=',') 加载时,我最终得到以下结果:

有没有办法得到想要的结果?


注意:或者,我会接受这个结果:


使用的版本:

  • Python:2.7.8
  • 熊猫 0.16.0

【问题讨论】:

    标签: python python-2.7 csv pandas


    【解决方案1】:

    你可以阅读:

        df = pd.read_csv('file.csv', header=[0, 1], skipinitialspace=True, tupleize_cols=True)
    

    然后

        df.columns = pd.MultiIndex.from_tuples(df.columns)
    

    【讨论】:

    • 我得到的结果与pd.read_csv(file, header=[0,1]) 得到的结果完全相同
    • 你能粘贴你的csv文件的样本吗?
    • @unutbu 很乐意在原始问题中添加 csv 代码(谢谢!)
    【解决方案2】:

    没有神奇的方法可以让 pandas 知道您希望索引的外观,最接近的方法是自己指定很多,如下所示:

    names = ['A', 'B', 
             ('C','X'), ('C', 'Y'), ('C', 'Z'),
             ('D','X'), ('D','Y'), ('D', 'Z')]
    pd.read_csv(file, mangle_dupe_cols=True,
                header=1, names=names, index_col=[0, 1])
    

    给:

         C        D      
         X  Y  Z  X  Y  Z
    A B                  
    1 2  3  4  5  6  7  8
    

    要以动态方式执行此操作,您可以按原样读取 CSV 的前两行,并遍历您获得的列以在加载完整数据集之前动态生成名称变量。

    pd.read_csv(file, nrows=1, header=[0,1], index_col=[0, 1])
    

    然后访问列并循环创建您的标题。 同样,这不是一个非常干净的解决方案,但应该可以工作。

    【讨论】:

    • 问题在于 csv 文件:1)有很多列; 2) 由另一个程序自动生成,因此列会随着时间的推移而改变。我猜有一种方法可以编写一个函数在第一级循环,如果为空,重命名为左边的那个还是什么?
    【解决方案3】:

    这是一种自动修复列索引的方法。第一的, 将列级值拉入 DataFrame:

    columns = pd.DataFrame(df.columns.tolist())
    

    然后将Unnamed: 列重命名为NaN

    columns.loc[columns[0].str.startswith('Unnamed:'), 0] = np.nan
    

    然后向前填充 NaN:

    columns[0] = columns[0].fillna(method='ffill')
    

    所以columns 现在看起来像

    In [314]: columns
    Out[314]: 
         0  1
    0  NaN  A
    1  NaN  B
    2    C  X
    3    C  Y
    4    C  Z
    5    D  X
    6    D  Y
    7    D  Z
    

    现在我们可以找到剩余的 NaN 并用空字符串填充它们:

    mask = pd.isnull(columns[0])
    columns[0] = columns[0].fillna('')
    

    要使前两列AB 可索引为df['A']df['B']——就好像它们是单级的——你可以交换第一列和第二列中的值:

    columns.loc[mask, [0,1]] = columns.loc[mask, [1,0]].values
    

    现在您可以构建一个新的 MultiIndex 并将其分配给df.columns

    df.columns = pd.MultiIndex.from_tuples(columns.to_records(index=False).tolist())
    

    把它们放在一起,如果data

    ,,C,,,D,,
    A,B,X,Y,Z,X,Y,Z
    1,2,3,4,5,6,7,8
    3,4,5,6,7,8,9,0
    

    然后

    import numpy as np
    import pandas as pd
    df = pd.read_csv('data', header=[0,1], sep=',')
    columns = pd.DataFrame(df.columns.tolist())
    columns.loc[columns[0].str.startswith('Unnamed:'), 0] = np.nan
    columns[0] = columns[0].fillna(method='ffill')
    mask = pd.isnull(columns[0])
    columns[0] = columns[0].fillna('')
    columns.loc[mask, [0,1]] = columns.loc[mask, [1,0]].values
    df.columns = pd.MultiIndex.from_tuples(columns.to_records(index=False).tolist())
        print(df)
    

    产量

       A  B  C        D      
             X  Y  Z  X  Y  Z
    0  1  2  3  4  5  6  7  8
    1  3  4  5  6  7  8  9  0
    

    【讨论】:

      【解决方案4】:

      使用多索引加载数据框:

      df = pd.read_csv(filelist,header=[0,1], sep=',')
      

      写一个函数来替换索引:

      def replace_index(df):
          arr = df.columns.values
          l = [list(x) for x in arr]
          for i in range(len(l)):
              if l[i][0][:7] == 'Unnamed':
                  if l[i-1][0][:7] != 'Unnamed':
                      l[i][0] = l[i-1][0]
          for i in range(len(l)):
              if l[i][0][:7] == 'Unnamed':
                      l[i][0] = l[i][1]
                      l[i][1] = ''
          index = pd.MultiIndex.from_tuples(l)
          df.columns = index
          return df
      

      返回正确索引的新数据框:

      replace_index(df)
      

      【讨论】:

        【解决方案5】:

        我使用一种技术从多索引列中展平并制作一列。对我来说效果很好。

        your_df.columns = ['_'.join(col).strip() for col in your_df.columns.values]
        

        【讨论】:

          【解决方案6】:

          导入提供标题行索引的 csv 文件:

          df = pd.read_csv('file.csv', header=[0, 1, 2])
          

          然后,您可以遍历每个列标题,清理它,将其分配给一个元组,然后使用 pd.MultiIndex.from_tuples(list_of_tuples) 重新分配数据帧列

          df.columns = pd.MultiIndex.from_tuples(
          [tuple(['' if y.find('Unnamed')==0 else y for y in x]) for x in df.columns]
          )
          

          这是我在尝试解决此问题时一直在寻找的快速单线。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2018-05-04
            • 2018-07-29
            • 2021-09-30
            • 2020-11-12
            • 2013-12-05
            • 2015-06-02
            • 2021-04-12
            相关资源
            最近更新 更多