以特定格式将“字典中的字典”写入 .csv 文件

Posted

技术标签:

【中文标题】以特定格式将“字典中的字典”写入 .csv 文件【英文标题】:writing "dictionary of dictionaries" to .csv file in a particular format 【发布时间】:2015-10-04 20:53:21 【问题描述】:

我正在从多个 .csv 文件中生成一个字典,它看起来像这样(示例):

dtDict = 'AV-IM-1-13991730': '6/1/2014 0:10': '0.96',
                      '6/1/2014 0:15': '0.92',
                      '6/1/2014 0:20': '0.97',
 'AV-IM-1-13991731': '6/1/2014 0:10': '1.96',
                      '6/1/2014 0:15': '1.92',
                      '6/1/2014 0:20': '1.97',
 'AV-IM-1-13991732': '6/1/2014 0:10': '2.96',
                      '6/1/2014 0:15': '2.92',
                      '6/1/2014 0:20': '2.97',
 'AV-IM-1-13991733': '6/1/2014 0:10': '3.96',
                      '6/1/2014 0:15': '3.96',
                      '6/1/2014 0:20': '3.97'

我想将其保存为以下格式的 .csv 文件:

timestamp,AV-IM-1-13991730,AV-IM-1-13991731,AV-IM-1-13991732,AV-IM-1-13991733
6/1/2014 0:10,0.96,1.96,2.96,3.96
6/1/2014 0:15,0.92,1.92,2.92,3.96
6/1/2014 0:20,0.97,1.97,2.97,3.97

我现在拥有的一段代码(与这个目标相关):

header = '''# file...... Recorder file
# date...... Thu Mar 12 14:35:32 2015
# user...... Sri
# host...... (null)
# group..... None
# property.. AVA Measurements
# limit..... 
# interval..''' 

testpower        = open("custpower.csv",'w')
testpower.writelines([header,'\n','# timestamp\n'])
...
for key, value in dtDict.iteritems():
    #Still trying to figure out how to write to custpower.csv

我尝试做类似的事情:

for key, value in dtDict.iteritems():
    testpower.writelines([key,',',','.join(value),'\n'])

但它并没有完全做到我想要做的。

【问题讨论】:

【参考方案1】:

试试这个:

outStr = ''
for key, value in dtDict.iteritems():
    outStr += str(key) + ','

outStr = outStr[:-1]
print outStr

valueStr1 = '6/1/2014 0:10'
valueStr2 = '6/1/2014 0:15'
valueStr3 = '6/1/2014 0:20'

for keys, values in dtDict.iteritems():
    for key, value in values.iteritems():
        if key == '6/1/2014 0:10':
            valueStr1 += str(value)
        if key == '6/1/2014 0:15':
            valueStr2 += str(value)
        if key == '6/1/2014 0:20':
            valueStr3 += str(value)

print valueStr1
print valueStr2
print valueStr3

当然不是print,而是写入文件。

编辑:考虑到下面的混乱

【讨论】:

它不工作。打印输出看起来像(用 , 替换 +):AV-IM-1-13991730,AV-IM-1-13991731,AV-IM-1-13991732,AV-IM-1-13991733 ('6/1/2014 0:10', '0.96') ('6/1/2014 0:20', '0.97') ('6/1/2014 0:15', '0.92') ('6/1/2014 0:10', '1.96') ('6/1/2014 0:20', '1.97') ('6/1/2014 0:15', '1.92') ('6/1/2014 0:10', '2.96') ('6/1/2014 0:20', '2.97') ('6/1/2014 0:15', '2.92') ('6/1/2014 0:10', '3.96') ('6/1/2014 0:20', '3.97') ('6/1/2014 0:15', '3.97') strange 在我的电脑上工作正常,可能会在写入文件时添加'\n' 转义字符。我将编辑我的答案。 您的代码正在做的是创建时间的多个实例(就像我在上面的评论中粘贴的那样)但是 .csv 中的输出应该看起来像我在问题中显示的示例输出,即只有应该创建一个时间戳,并且应该将值附加在用逗号分隔的同一行中(如我的问题所示)。 不确定你在我的代码中得到了什么给我以下输出,AV-IM-1-13991730,AV-IM-1-13991731,AV-IM-1-13991732,AV-IM-1-13991733 6/1/2014 0:100.96 6/1/2014 0:200.97 6/1/2014 0:150.92 6/1/2014 0:101.96 6/1/2014 0:201.97 6/1/2014 0:151.92 6/1/2014 0:102.96 6/1/2014 0:202.97 6/1/2014 0:152.92 6/1/2014 0:103.96 6/1/2014 0:203.97 6/1/2014 0:153.96 它不会以这种格式显示,但它与您在原始帖子中发布的格式相同。【参考方案2】:

您可以像这样将数据重新组织到一个新的列表结构字典中。请记住,这将在打印之前读取整个文件(它必须获取第一个时间戳的最后一个值)。因此,如果您的输入很大,它可能会很慢。此外,字典不会按任何特定顺序保存它们的键,因此如果顺序很重要,您可能需要将键保存在单独的列表中。

ts = dtDict.keys()

print "timestamp," + ",".join(ts)   
reformatted = 

for k in ts:
    sub_dict = dtDict[k]
    for timestamp in sub_dict.keys():
        value = sub_dict[timestamp]
        if not reformatted.has_key(timestamp):
            reformatted[timestamp] = []
        reformatted[timestamp].append(value)

for rec in reformatted.keys():
    print rec + " " + ",".join(reformatted[rec])

当然,如果时间戳的集合总是一致的,你可以做一些更简单的事情:

datasets = dtDict.keys()
timestamps = dtDict[datasets[0]].keys()


for ts in timestamps:
    values = []
    for ds in datasets:
        values.append(dtDict[ds][ts])
    print ts + " " + "".join(values)

同样,除非您提前设置顺序,否则它将以任意顺序显示。因此,无需从字典本身设置时间戳,您只需提前阅读它们即可。

【讨论】:

时间步长和时间戳是一致的。在我实现您的代码以写入 .csv 文件之前,如何按时间升序对字典进行排序? 字典不能按顺序存储东西,但你可以保留一个单独的键列表:dtDict = "6:15" : "0.9", "6:10" : "0.8", 6:20" : "0.2"timestamps_in_order = ["6:10", "6:15","6:20"] 然后,而不是循环通过data.keys()循环通过timestamps_in_order和引用键的数据。如何制作时间戳列表取决于您的输入。你可能可以逃脱惩罚:timestamps_in_order = dtDict[datasets[0]].keys()timestamps_in_order.sort()【参考方案3】:

要浏览您的 AV-IM-1-139917XX 代码和日期,字典词典有点麻烦。由于当我们调用dtDict.iteritems() 之类的东西时我们无法保证顺序,我们需要将键作为列表获取并对其进行排序。我使用 ID (AV-IM-1-139917XX) 和日期列表来执行此操作。

这就是我想出的。它可能很难看,但它有效:

编辑:将sorted添加到dtDict.keys()

dates = []
av_im = sorted(dtDict.keys())

for k, v in dtDict.iteritems():
    dates = v.keys()  # this returns a list of date keys

dates = sorted(list(set(dates)))  # remove duplicates and sort
print dates  # ['6/1/2014 0:10', '6/1/2014 0:15', '6/1/2014 0:20']
print av_im  # ['AV-IM-1-13991730', 'AV-IM-1-13991731', 'AV-IM-1-13991732', 'AV-IM-1-13991733']

这会得到我需要在您的字典中导航的值列表。所以现在我可以这样做了:

csv_list = []
for date in dates:
    s = str(date)
    for code in av_im:
        s = s +','+str(dtDict[code][date])
    csv_list.append(s)

print csv_list  # ['6/1/2014 0:10,0.96,1.96,2.96,3.96', '6/1/2014 0:15,0.92,1.92,2.92,3.96', '6/1/2014 0:20,0.97,1.97,2.97,3.97']

现在我们可以写入 csv:

import csv
with open('mycsv.csv', 'w') as f:
    w = csv.writer(f, delimiter = ',')
    w.writerows([s.split(',') for s in csv_list])

我们得到一个如下所示的 csv:

6/1/2014 0:10,0.96,1.96,2.96,3.96
6/1/2014 0:15,0.92,1.92,2.92,3.96
6/1/2014 0:20,0.97,1.97,2.97,3.97

根据需要自定义以包含您的标题...

需要考虑的一些事项:在示例中,您给出的日期/时间很容易排序。如果您的真实数据集跨越多天或使用 12 小时制或其他比您显示的更复杂的东西,那么您应该将日期/时间的唯一列表转换为 datetime 对象列表并对它们进行排序。

【讨论】:

【参考方案4】:

如果您可以使用pandas,这将非常简单。

import pandas as pd

data = 'AV-IM-1-13991730': '6/1/2014 0:10': '0.96',
                             '6/1/2014 0:15': '0.92',
                             '6/1/2014 0:20': '0.97',
        'AV-IM-1-13991731': '6/1/2014 0:10': '1.96',
                             '6/1/2014 0:15': '1.92',
                             '6/1/2014 0:20': '1.97',
        'AV-IM-1-13991732': '6/1/2014 0:10': '2.96',
                             '6/1/2014 0:15': '2.92',
                             '6/1/2014 0:20': '2.97',
        'AV-IM-1-13991733': '6/1/2014 0:10': '3.96',
                             '6/1/2014 0:15': '3.96',
                             '6/1/2014 0:20': '3.97'

df = pd.DataFrame(data)
df.to_csv(PATH_TO_OUTPUT_FILE)

df 变成了一个 DataFrame,看起来像

              AV-IM-1-13991730 AV-IM-1-13991731 AV-IM-1-13991732 AV-IM-1-13991733
6/1/2014 0:10             0.96             1.96             2.96             3.96
6/1/2014 0:15             0.92             1.92             2.92             3.96
6/1/2014 0:20             0.97             1.97             2.97             3.97

你生成的 csv 看起来像

,AV-IM-1-13991730,AV-IM-1-13991731,AV-IM-1-13991732,AV-IM-1-13991733
6/1/2014 0:10,0.96,1.96,2.96,3.96
6/1/2014 0:15,0.92,1.92,2.92,3.96
6/1/2014 0:20,0.97,1.97,2.97,3.97

Pandas 也不错,因为你可以这样做:

df.convert_objects(convert_numeric=True).plot()
# the converts change "0.97" -> 0.97 so it's plottable

获得:

【讨论】:

这非常简单。我需要阅读 DataFrame 我将在整个文件 (550MB) 上尝试此代码并进行测试 与我的回答相比,这非常简单。 @Scott 我尝试制作一个像[(timestamp, header, value) for header, d in data.items() for timestamp, value in d.items()] 这样的数据点列表并从那里开始,但我无法做出任何不比罪恶更丑陋的工作。最终我想“我想知道我是否足够了解 pandas 以将数据转移到这里需要的地方。”结果这一切都到了它应该去的地方——我很幸运! 是的,我正在尝试一些巧妙的解包和 itertools.groupby,但无法提出任何建议。很高兴看到熊猫可以轻松做到这一点。 貌似pandas也是自动排序的还是列和行排序只是巧合?

以上是关于以特定格式将“字典中的字典”写入 .csv 文件的主要内容,如果未能解决你的问题,请参考以下文章

如何在文件中写入 YAML 格式的数据?

python csv写入的字符串是啥格式

通过合并空白主字典中的字典,在 Python 中创建具有特定结构的 JSON

如何强制Python XlsxWriter以自定义格式写入单元格

读取csv字典变成str了怎么办

从 Python 中的 csv 创建字典中的字典列表