Python:使用多个标题行写入 CSV

Posted

技术标签:

【中文标题】Python:使用多个标题行写入 CSV【英文标题】:Python: Write to CSV with multiple header rows 【发布时间】:2019-02-12 14:42:58 【问题描述】:

上下文

我希望导出一个字典,其中包含字典列表作为每个 key:value 对的值:

dict = 'key_1':
        ['key_a': foo_1, 'key_b': bar_1, 
         'key_a': foo_2, 'key_b': bar_2], 
        'key_2':
        ['key_c': foo_1, 'key_d': bar_1], 
         'key_c': foo_2, 'key_d': bar_2] 
        ...

所需的输出将是一个 .csv 文件,其中包含第一个字典的键(key_1、key_2 等)作为第一个标题行,然后是嵌套字典的键(key_a、key_b 等) , 作为对应于其各自键的第二个标题行。

所需输出的示例如下所示,其中列表索引列引用存储在字典列表中每个相应索引处的字典中的数据:

╔════════════╦═══════════════╤═══════════════╗
║            ║     key_1     │     key_2     ║
║ List Index ╠═══════╤═══════╪═══════╤═══════╣
║            ║ key_a │ key_b │ key_c │ key_d ║
╠════════════╬═══════╪═══════╪═══════╪═══════╣
║     0      ║ foo_1 │ bar_1 │ foo_1 │ bar_1 ║
╟────────────╫───────┼───────┼───────┼───────╢
║     1      ║ foo_2 │ bar_2 │ foo_2 │ bar_2 ║
╟────────────╫───────┼───────┼───────┼───────╢
║     2      ║ foo_3 │ bar_3 │ foo_3 │ bar_3 ║
╚════════════╩═══════╧═══════╧═══════╧═══════╝

平台: 树莓派 3b+、Python 3.6


代码

目前,我正在研究执行此操作的不同选项,因此没有任何接近工作的连贯代码。但是,按照优先顺序,我正在考虑以下几个选项:

使用 pandas 形成一个反映所需表性质的数组。然后直接将其写入 CSV。

从上述字典数据结构写入 CSV。

import csv

field_names = dict.keys()
header2 = '%s' %dict.keys() : dict[key_1][0].keys()

with open('project_data.csv', 'a') as csvfile:
    writer = csv.DictWriter(csvfile, fieldnames=field_names)
    writer.writeheader()  # Write header row containing the top field names
    writer.writerow(header2)  #Write row containing the second field names

显然,此代码需要进一步开发以使其按预期工作。

另一种我没有考虑过的方法?


问题

以这种格式写入 CSV 的最佳方法是什么?

【问题讨论】:

我在这里解决了一个类似的问题:***.com/questions/52001109/arrays-to-row-in-pandas/… @anky_91 谢谢,这为使用 pandas 执行此操作提供了一个很好的过程。关于如何使用多个标题行执行此操作的任何想法?这才是真正让我难过的地方。 【参考方案1】:

到目前为止,我已经到达这里:

d = 'key_1':
    ['key_a': 'foo_1', 'key_b': 'bar_1', 
     'key_a': 'foo_2', 'key_b': 'bar_2'], 
    'key_2':
    ['key_c': 'foo_1', 'key_d': 'bar_1', 
     'key_c': 'foo_2', 'key_d': 'bar_2']
df = pd.DataFrame(d)
df1 = []
for col in df.columns:
    data = df[col].apply(pd.Series)
    data = df1.append(data)
df1 = pd.concat(df1,axis=1)
print(df1)

给你:

  key_a   key_b    key_c     key_d
0 foo_1   bar_1    foo_1     bar_1 
1 foo_2   bar_2    foo_2     bar_2 

剩下的,你必须将相应的键映射到你的原始列名,并且可以将 tat 作为标识符放在 df1.loc[-1] 中。一旦我得到一些东西,我会更新。

【讨论】:

这很好用,经过进一步研究,我不确定是否可以根据需要创建包含合并单元格的第二个标题行。这是因为 CSV 不包含任何单元格样式信息,因此无法合并单元格。这意味着可能需要为每个***标题(key_1、key_2 等)形成一个新的 csv 文件。我会对这个的任何替代品感兴趣。 我不确定如何格式化或合并 csv 单元格,但是我会尝试看看是否可以提出 key1: key_a...etc 映射。 :)【参考方案2】:

您的“列表索引”是一个合并单元格,您无法在 CSV 文件中实现,因为它不包含格式。您可以:

a) 将其写入 xlsx 文件(XlsxWriter 是一个很棒的库)

b) 保持它是 CSV,但按照 anky_91 的建议,使用未合并的单元格

【讨论】:

【参考方案3】:

这是为包含字典和字典列表的字典创建 DictWriter()fieldnames 的解决方案。

您需要遍历结构并生成 fieldnames 以及具有这些新名称的新 dict

#!/usr/bin/env python3
import csv
import pprint as pp

myDict = 'key_1':
        ['key_a': 'foo_1', 'key_b': 'bar_1', 
         'key_a': 'foo_2', 'key_b': 'bar_2'], 
        'key_2':
        ['key_c': 'foo_1', 'key_d': 'bar_1', 
         'key_c': 'foo_2', 'key_d': 'bar_2'] 

def generateFieldnames(myDict):
    # create unique fieldnames from a dictionary containing dictionaries
    newDict=
    fieldnames=[] # DictWriter will create a .csv with these header names
    
    for k,v in myDict.items():
        
        # is a dictionary?
        if (type(v) is dict):
            for kk,vv in v.items():
                print('k=0, kk=1, vv=2'.format(k,kk,vv))
                name='0_1'.format(k,kk)
                fieldnames.append(name)
                newDict[name]=vv
                
        elif (type(v) is list):
            for item in range(len(v)):
                listItem=v.pop()
                if (type(listItem) is dict):
                    for kk,vv in listItem.items():
                        name='0_1'.format(k,kk)
                        fieldnames.append(name)
                        newDict[name]=vv
        
        else:
            print('k=[0] , v=[1]'.format(k,v))
            fieldnames.append(k)
            newDict[k]=v
    
    return fieldnames, newDict


# create fieldnames from the dictionary with lists and dictionaries
fieldnames, newDict=generateFieldnames(myDict)
pp.pprint(fieldnames)
print('\n')
pp.pprint(fieldnames)
print('\n\n')

# write a sample .csv with fieldnames as headers
fd = open('mytest.csv','a')
dw = csv.DictWriter( fd, fieldnames=fieldnames)

dw.writeheader() # write the header row

dw.writerow( newDict )
dw.writerow( newDict )
dw.writerow( newDict )

fd.close()

结果可见文件mytest.csv:

key_1_key_a,key_1_key_b,key_1_key_a,key_1_key_b,key_2_key_c,key_2_key_d,key_2_key_c,key_2_key_d
foo_1,bar_1,foo_1,bar_1,foo_1,bar_1,foo_1,bar_1
foo_1,bar_1,foo_1,bar_1,foo_1,bar_1,foo_1,bar_1
foo_1,bar_1,foo_1,bar_1,foo_1,bar_1,foo_1,bar_1

【讨论】:

以上是关于Python:使用多个标题行写入 CSV的主要内容,如果未能解决你的问题,请参考以下文章

将具有多个标签的值写入 influxDB(使用 python)

如何使用 Apache Beam (Python) 将多个嵌套的 JSON 写入 BigQuery 表

AWS Lambda Python 读取所有行但不写入所有行

使用 Python 将列表中的数据帧写入多个 excel 文件

Python - 写入 CSV 文件和 for 循环

使用固定宽度行写入/解析文本文件