将CSV列中的值转换为单独的列
我有一个CSV文件,格式如下:
ID | STUFF | Custom | Custom Value
1 | string1 | name1 | val1
1 | string1 | name2 | val2
1 | string1 | name3 | val3
2 | string2 | name1 | val4
2 | string2 | name3 | val5
3 | string3 | name2 | val6
等等...
关于这个CSV文件,关键是当前的自定义列里有很多“字段”,我需要把这些字段分出来,放到自己的列里,并且把它们的值放在旁边的列中。这个自定义列里的值有点不确定,比如每个ID可能有不同的自定义“名称”。不过,我知道所有可能的“自定义”名称的完整列表。
我想要的输出结果是:(注意:我意识到我之前说的输出需求有点错误,现在已经更正了)
ID | STUFF | name1 | name2 | name3
1 | SomeText | name1_Value | name2_Value| name3_Value
2 | SomeText | name1_Value | name2_Value| name3_Value
我对Python还比较陌生,现在在想怎么优雅地实现这个功能时遇到了困难,感觉需要很多次循环。我的想法是使用CSV模块和DictReader配合元组来解决这个问题,但目前我还在挣扎。我这个文件大约有1200行,只需要处理一次,但我想学习在Python中做事情的最佳方法。
2 个回答
0
csv模块绝对是个不错的起点。
我会为每个ID建立一个字典,把字段名和对应的值关联起来。例如,对于ID 1:
{'STUFF':'String 1', 'name1':'val1', 'name2':'val2', 'name3':'val3'}
你可以把这些存放在一个列表里(如果你的ID是连续的整数),或者放在另一个字典里。
保持一个你见过的所有字段名的集合。然后使用csv的DictWriter把结果输出成你想要的格式。遍历你的列表(用enumerate
)或者字典(用d.iteritems()
),把ID再加回每个字典里,然后发送给writerow。
0
你可以这样做(假设csv文件中的行是按id排序的):
import csv, itertools, operator
with open('data.csv', 'rb') as infile:
results = []
# uses the header row to get field names, each row will be a dict
rows = csv.DictReader(infile)
# keeps track of all the custom names we've seen
all_custom_vals = set()
for id_val, group in itertools.groupby(rows, operator.itemgetter('ID')):
collapsed_row = {}
for row in group:
collapsed_row['ID'] = row['ID']
collapsed_row['STUFF'] = row['STUFF']
collapsed_row[row['Custom']] = row['Custom Value']
all_custom_vals.add(row['Custom'])
results.append(collapsed_row)
itertools.groupby
在这种情况下非常有用。
然后,results
将会是一个字典的列表,你可以用下面的方式把它写成csv格式:
import sys
writer = csv.writer(sys.stdout)
keys = sorted(all_custom_vals)
writer.writerow(['ID', 'STUFF'] + keys)
for row in results:
items = [row['ID'], row['STUFF']]
for key in keys:
items.append(row.get(key, '<no value>'))
writer.writerow(items)
把 <no value>
替换成当没有对应自定义名称的行时应该显示的值。
补充说明:其实,我给出的输出结果并不是你最初要求的(不过我觉得可能更有用)。如果你想要完全符合你要求的结果,你需要把第二部分改成:
import sys
writer = csv.writer(sys.stdout)
keys = sorted(all_custom_vals)
for row in results:
items = [row['ID'], row['STUFF']]
for key in keys:
items.append(key)
items.append(row.get(key, '<no value>'))
writer.writerow(items)