从动态字典创建矩阵

3

I want to create a matrix.

Input:

data = [
    {'a': 2, 'g': 1},
    {'p': 3, 'a': 5, 'cat': 4}
    ...
]

输出:

     a  p  cat  g
1st  2  0  0    1
2nd  5  3  4    0

这是我的代码。但我认为,当数据量很大时,它既不聪明又非常缓慢

有没有好的方法来处理这个问题?

谢谢。

data = [
    {'a': 2, 'g': 1},
    {'p': 3, 'a': 5, 'cat': 4}
]

### Get keyword map ###
key_map = set()
for row in data:
    key_map = key_map.union(set(row.keys()))

key_map = list(key_map)    # ['a', 'p', 'g', 'cat']

### Create matrix ###
result = []
for row in data:
    matrix = [0] * len(key_map)
    for k, v in row.iteritems():
        matrix[key_map.index(k)] = v
    result.append(matrix)

print result        

# [[2, 0, 0, 1], [5, 3, 4, 0]]

编辑

通过@wwii的建议。使用Pandas好像不错:

from pandas import DataFrame

result = DataFrame(data, index=range(len(data)))
print result.fillna(0, downcast=int).as_matrix().tolist()
# [[2, 0, 1, 0], [5, 4, 0, 3]]
4个回答

4
你可以使用集合推导式来生成 key_map
key_map = list({data for row in data for data in row})

我测试了这段代码,确实比我的快很多,怎么做到的? - fyr91
感谢您的建议。 :) - Puffin GDI
@fyr0049,这被称为集合推导式。推导式是Python灵魂中内置的功能。 - thefourtheye

2
这里是部分答案。我无法按指定顺序获取列 - 它受到在集合key_map中排序键的限制。它使用字符串格式化来排列数据 - 您可以调整间距以适应更大或更小的数字。
# ordinal from
# http://code.activestate.com/recipes/576888-format-a-number-as-an-ordinal/
from ordinal import ordinal

data = [
    {'a': 2, 'g': 1},
    {'p': 3, 'a': 5, 'cat': 4}
]

### Get keyword map ###
key_map = set()
for row in data:
    key_map = key_map.union(set(row.keys()))

key_map = list(key_map)    # ['a', 'p', 'g', 'cat']

# strings to format the output
header = '{: >10}{: >8}{: >8}{: >8}'.format(*key_map)
line_fmt = '{: <8}{: >2}{: >8}{: >8}{: >8}'
print header

def ordered_data(d, keys):
    """Returns an ordered list of dictionary values.

    returns 0 if key not in d
    d --> dict
    keys --> list of keys
    returns list
    """
    return [d.get(key, 0) for key in keys]

for i, thing in enumerate(data):
    print line_fmt.format(ordinal(i+1), *ordered_data(thing, key_map))

输出

         a       p       g     cat
1st      2       0       1       0
2nd      5       3       0       4

值得一提的是,深入研究Pandas文档并查看其DataFrame可能会使生活更加轻松。


看起来我可能又误读了问题!我会保留它并观察发生了什么。 - wwii
好的,我会尝试使用Pandas。谢谢。 - Puffin GDI

1

我赞同使用Pandas数据框的回答。不过,我的代码应该比你的简单一些。

In [1]: import pandas as pd

In [5]: data = [{'a': 2, 'g': 1},{'p': 3, 'a': 5, 'cat': 4}]

In [6]: df = pd.DataFrame(data)

In [7]: df
Out[7]: 
   a  cat   g   p
0  2  NaN   1 NaN
1  5    4 NaN   3

In [9]: df = df.fillna(0)

In [10]: df
Out[10]: 
   a  cat  g  p
0  2    0  1  0
1  5    4  0  3

我在iPython中进行编码,强烈推荐使用它!
如果要保存为CSV文件,只需要使用一行额外的代码:
df.to_csv('filename.csv')

0

我是Python的新手,只是提供一些希望有所帮助的建议:)

key_map = []
for row in data:
    key_map.extend(row.keys())
key_map = list(set(key_map))

你可以将中间部分改成这样,这样可以节省你寻找 key_map 的时间。
在你的情况下,union 至少会扫描每一行来找到不同的项。

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