【问题标题】:Python: Write to CSV with multiple header rowsPython:使用多个标题行写入 CSV
【发布时间】: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 的最佳方法是什么?

【问题讨论】:

标签: python pandas csv dictionary data-structures


【解决方案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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-08-03
      • 2018-05-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-07
      • 1970-01-01
      • 2019-12-18
      相关资源
      最近更新 更多