【问题标题】:How to insert a second header row in pandas df for csv write如何在 pandas df 中插入第二个标题行以进行 csv 写入
【发布时间】:2016-04-29 14:39:07
【问题描述】:

我有一个非常大的 pandas df 我正在写到 csv。我需要添加包含数据类型的第二个标题行。下面的代码有效,但在 CSV 中产生了第三个意外的空行:

#! /usr/bin/env python
import pandas as pd

df = pd.DataFrame([[1, 2], [3, 4]], columns=list('AB'))

# get count of header columns, add REAL for each one
types_header_for_insert = list(df.columns.values)
for idx, val in enumerate(types_header_for_insert):
    types_header_for_insert[idx] = 'REAL'

# count number of index columns, then add STRING for each one
index_count = len(df.index.names)
for idx in range(0, index_count):
    df.reset_index(level=0, inplace=True)
    types_header_for_insert.insert(0, 'STRING')

# insert the new types column
df.columns = pd.MultiIndex.from_tuples(zip(df.columns, types_header_for_insert))

print df.columns.values

df.to_csv("./test.csv", index=False)

输出:

index,A,B
STRING,REAL,REAL
,,
0,1,2
1,3,4

我怎样才能摆脱这个多余的空白行?它来自哪里?

【问题讨论】:

    标签: python csv pandas export-to-csv


    【解决方案1】:

    我认为这是错误,请参阅opened issue 6618

    也许有帮助的小技巧 - 在数据的第一行之前添加types_header_for_insert

    #! /usr/bin/env python
    import pandas as pd
    
    df = pd.DataFrame([[1, 2], [3, 4]], columns=list('AB'))
    
    # get count of header columns, add REAL for each one
    types_header_for_insert = list(df.columns.values)
    for idx, val in enumerate(types_header_for_insert):
        types_header_for_insert[idx] = 'REAL'
    
    # count number of index columns, then add STRING for each one
    index_count = len(df.index.names)
    for idx in range(0, index_count):
        df.reset_index(level=0, inplace=True)
        types_header_for_insert.insert(0, 'STRING')
    
    # insert the new types column
    #df.columns = pd.MultiIndex.from_tuples(zip(df.columns, types_header_for_insert))
    
    #set new value to dataframe
    df.loc[-1]  = types_header_for_insert
    
    #sort index 
    df = df.sort_index()
    print df
    #     index     A     B
    #-1  STRING  REAL  REAL
    # 0       0     1     2
    # 1       1     3     4
    
    print df.to_csv(index=False)
    #index,A,B
    #STRING,REAL,REAL
    #0,1,2
    #1,3,4
    

    编辑

    在大的df中你可以使用append:

    #empty df with column from df
    df1 = pd.DataFrame(columns = df.columns)
    #create series from types_header_for_insert
    s = pd.Series(types_header_for_insert, index=df.columns)
    print s
    index    STRING
    A          REAL
    B          REAL
    dtype: object
    
    df1 = df1.append(s, ignore_index=True).append(df, ignore_index=True)
    print df1
        index     A     B
    0  STRING  REAL  REAL
    1       0     1     2
    2       1     3     4
    
    print df1.to_csv(index=False)
    index,A,B
    STRING,REAL,REAL
    0,1,2
    1,3,4
    

    【讨论】:

    • 是的,工作但排序操作在具有更复杂的多键索引的大表上效率不高(我的数据帧需要 30 分钟排序)。在这种情况下,创建具有单行和相同标题的新数据框然后合并而不是追加和排序可能更有效。
    【解决方案2】:

    在 Python 3 中,MultiIndex.from_tuples() 失败,“zip”类型的对象没有 len()。但是,将 zip 包裹在 list() 中不会出现空白行。考虑在 Python 2 中尝试:

    df.columns = pd.MultiIndex.from_tuples(list(zip(df.columns, types_header_for_insert)))
    
    print df.columns.values
    
    df.to_csv("./test.csv", index=False)
    
    #   index    A    B
    #  STRING REAL REAL
    #       0    1    2
    #       1    3    4
    

    或者,使用列表理解环绕zip

    data = [df.columns, types_header_for_insert]
    newcolumns = [tuple(i[j] for i in data) for j in range(min(len(l) for l in data))]
    df.columns = pd.MultiIndex.from_tuples(newcolumns)
    
    print df.columns.values
    
    df.to_csv("./test.csv", index=False)
    
    #   index    A    B
    #  STRING REAL REAL
    #       0    1    2
    #       1    3    4
    

    【讨论】:

    • 第一种使用 list(zip()) 的方法仍然给我 pandas 0.16.1 中的空白行 - 由于各种原因,我无法更新他的观点。 @jezrael 指出这个已知的错误是原因 - issue 6618
    • 第二种方法也没有运气 - 避免使用 zip 的方法仍然会给出第三个空行,就像我的第一个代码 sn-p ",," 中一样。这是什么pd版本的?
    【解决方案3】:

    我最后使用了一种解决方法 (a) 将原始标题写入 csv (b) 用第二个标题行替换标题并将整个 df 附加到第一个文件:

    # write the header to the file only
    pd.DataFrame(data=[df.columns]).to_csv("outfile.csv", header=False, index=False)
    
    # now replace header
    types_header_for_insert = list(df.columns.values)
    for idx, val in enumerate(df.columns.values):
        if df[val].dtype == 'float64':
            types_header_for_insert[idx] = 'REAL'
    
        elif self.grouped[val].dtype == 'int64':
            types_header_for_insert[idx] = 'INTEGER'
    
        else:
            types_header_for_insert[idx] = 'STRING'
    
    df.columns = types_header_for_insert
    
    # append the whole df with new header
    df.to_csv("outfile.csv", mode="a", float_format='%.3f', index=False)
    

    【讨论】:

      猜你喜欢
      • 2019-01-31
      • 1970-01-01
      • 2018-05-15
      • 2022-11-28
      • 2019-02-12
      • 2018-04-19
      • 2016-08-30
      • 2016-05-23
      • 1970-01-01
      相关资源
      最近更新 更多