【问题标题】:Python - Dictionary from CSV file with Multiple Values per KeyPython - 来自 CSV 文件的字典,每个键有多个值
【发布时间】:2014-03-20 13:00:06
【问题描述】:

我正在尝试从 python 中的 csv 文件制作字典。假设 CSV 包含:

Student   food      amount
John      apple       15
John      banana      20
John      orange      1
John      grape       3
Ben       apple       2
Ben       orange      4
Ben       strawberry  8
Andrew    apple       10
Andrew    watermelon  3

我所设想的是一个字典,其键是学生姓名和一个列表,作为每个条目对应于不同食物的值。 我必须计算第二列中独特食物的数量,这就是向量的长度。 例如:

The value of [15,20,1,3,0,0] would correspond to [apple, banana, orange, grape, strawberry, watermelon] for  'John'. 
The value of [2,0,4,0,8,0] would correspond to [apple, banana, orange, grape, strawberry, watermelon] for 'Ben'.
The value of [10,0,0,0,0,3] would correspond to [apple, banana, orange, grape, strawberry, watermelon] for 'Andrew'

dict 的预期输出如下所示:

dict={'John':{[15,20,1,3,0,0]}, 'Ben': {[2,0,4,0,8,0]}, 'Andrew': {[10,0,0,0,0,3]}}

我在创建字典时遇到了麻烦,或者字典是否是正确的方法。我必须从什么开始:

import csv
data_file=open('data.csv','rU')
reader=csv.DictReader(data_file)
data={}
for row in reader:
    data[row['Student']]=row
data_file.close()

感谢您花时间阅读。任何帮助将不胜感激。

【问题讨论】:

    标签: python csv dictionary


    【解决方案1】:

    这是一个使用普通字典的版本。不过 Defaultdict 肯定更好。

    import csv
    data_file=open('data.csv','rU')
    reader=csv.DictReader(data_file)
    data={}
    for row in reader:
        if row['Student'] in data:
            data[row['Student']].append(row['amount'])
        else:
            data[row['Student']] = [row['amount']]
    data_file.close()
    

    编辑:

    For matching indicies
    import csv
    from collections import defaultdict
    
    data_file=open('data.csv','rU')
    reader=csv.DictReader(data_file)
    data=defaultdict(lambda:[0,0,0,0])
    fruit_to_index = defaultdict(lambda:None,{'apple':0,'banana':1,'orange':2,'grape':3})
    for row in reader:
        if fruit_to_index[row['food']] != None:
            data[row['Student']][fruit_to_index[row['food']]] = int(row['amount'])
    data_file.close()
    

    print data 会是

    defaultdict(<function <lambda> at address>, 
    {'John':  [15, 20, 1, 3], 
    'Ben':    [2 , 0 , 0, 0], 
    'Andrew': [10, 0 , 0, 0]})
    

    我想这就是你想要的。

    编辑2: 当水果列表不包括草莓和西瓜时这样做,但应该很容易添加。 如果列表太大

    生成水果到索引的映射

    set_of_fruits = set()
    for row in reader:
        set_of_fruits.add(row['food'])
    c = 0
    for e in set_of_fruits:
        fruit_to_index[e] = c
        c += 1
    

    注意,set_of_fruits 的顺序是不会生成的。

    data = defaultdict(lambda:[0,0,0,0])变成

    data = defaultdict(lambda:[0 for x in range(len(set_of_fruits))])

    【讨论】:

    • 谢谢。但是,这只会添加到列表中,但不会将索引与食物名称匹配。例如,由于 Ben 没有吃橙子,因此金额将填充为 0。
    • 我想尽量避免对每个水果的索引进行硬编码,因为不幸的是,我的 csv 文件中有大约 200 个独特的水果。
    • 阅读编辑 2。您可以使用row['food'] 生成水果列表
    【解决方案2】:

    使用dict的setdefault方法。

    import csv
    data_file=open('data.csv','rU')
    reader=csv.DictReader(data_file)
    data={}
    for row in reader:
        data.setdefault(row['Student'], []).append(row['amount'])
    data_file.close()
    

    如果键,例如。 “John”,不存在,它使用提供的默认值创建它。在这种情况下,默认为空列表。

    【讨论】:

      【解决方案3】:

      您可能实际上想要一个嵌套的字典结构;保留一份清单,然后尝试将索引与食物名称相匹配,这会很快变得棘手。

      import csv
      from collections import defaultdict
      data = defaultdict(dict)
      with open('data.csv', 'r') as file:
          reader = csv.DictReader(file)
          for row in reader:
              data[row['Student']][row['food']] = row['amount']
      

      这会给你一个像这样的结构:

      {'John': {'apple': 15, 'banana': 20, 'orange': 1}, 
       'Ben': {'apple': 2, 'watermelon': 4}, #etc.
      }
      

      这使您可以查找特定食物,而无需尝试交叉引用另一个列表来找出在哪里可以找到计数,并且支持任意数量的食物项目,而不必为所有缺失的食物填写零。

      如果你想更花哨,你可以使用嵌套的defaultdict,这样查找没有输入的食物会自动返回零,而不是给KeyErrors;只需将第二行更改为:

      data = defaultdict(lambda: defaultdict(int))
      

      【讨论】:

      • 谢谢。我想我应该提到最终目标是什么。我正在尝试对不同学生之间的数量向量进行余弦相似性,所以我需要确保的是食物名称的索引与每个学生相匹配,如果他们没有那个食物名称,那么数量会填充 0
      【解决方案4】:

      试试这个,我想这就是你想要的。请注意defaultdict 的用法,它可以使用常规字典完成,但 defaultdict 在这种情况下非常方便:

      import csv
      from collections import defaultdict
      data=defaultdict(list)
      with open('data.csv','rb') as data_file:
          reader=csv.DictReader(data_file)
          for row in reader:
              data[row['Student']].append(row['amount'])
      

      【讨论】:

      • 谢谢。这只会添加到列表中,但不匹配食物名称的索引。
      • 那是因为你没有很准确地描述你的问题。请更正示例预期输出。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-10-28
      • 2011-06-09
      • 2015-07-25
      • 2019-07-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多