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

7
我正在将多个 .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'])

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

4个回答

12

如果你会使用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)上尝试此代码并测试它。 - Nikhil Gupta
1
与我的答案相比,那太简单了。 - Scott
@Scott 我尝试制作了一个数据点列表,类似于[(时间戳,标题,数值) for 标题, d in data.items() for 时间戳, 数值 in d.items()],并从那里继续进行,但是我无法做出任何比罪孽还难看的东西。最后我想:“我是否已经足够熟悉 pandas,在这里将数据移动到它需要去的地方。” 结果所有数据都到了它应该去的地方——我很幸运! - Adam Smith
是啊,我一直在尝试使用巧妙的解包和itertools.groupby,但却无法想出任何方法。很高兴看到Pandas可以很容易地完成这个任务。 - Scott
看起来pandas自动排序,还是列和行被排序只是巧合? - Scott
@Scott 我真的说不准。由于原始数据是字典,它们可能是自然而然地按照这种方式排序的,或者可能是pandas提供了某种排序方式。我不确定。 - Adam Smith

1
你可以将数据重新组织成一个新的字典列表结构,就像这样。请记住,在打印之前,它会读取整个文件(必须获取第一个时间戳的最后一个值)。因此,如果输入很大,它可能会变慢。此外,字典不保留其键的任何特定顺序,因此如果顺序很重要,您可能希望将键保存在单独的列表中。
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 文件之前,我该如何按升序排序字典? - Nikhil Gupta
字典无法按顺序存储数据,但您可以保留一个键的单独列表: 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() - ate50eggs

1
字典的字典在浏览您的AV-IM-1-139917XX代码和日期时有点繁琐。由于我们无法保证调用dtDict.iteritems()时的顺序,因此我们需要将键作为列表获取并进行排序。我用ID(AV-IM-1-139917XX)和日期列表都做了这个操作。
这就是我想到的。它可能很丑陋,但它有效。
(编辑:在dtDict.keys()中添加了sorted
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对象列表并对其进行排序。


0

试试这个:

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
编辑:考虑到下面的混淆

在我的电脑上奇怪的东西运行良好,也许在写入文件时添加 '\n' 转义字符。我会编辑我的答案。 - DrBwts
你的代码正在创建多个时间实例(就像我在上面的评论中粘贴的那样),但是.csv文件的输出应该看起来像我在问题中展示的示例输出,即只应该创建一个时间戳,并且值应该以逗号分隔附加在同一行中(如我在问题中所示)。 - Nikhil Gupta
不确定你的意思,我的代码输出如下: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 - DrBwts
它不会以与您在原始帖子中发布的格式相同的格式显示。 - DrBwts
啊,不好意思,我收回之前的话:D - DrBwts
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接