Python 添加元组元素,解析为数据帧

Python 添加元组元素,解析为数据帧,python,pandas,Python,Pandas,我有几个元组的Python列表: [(0, 61), (1, 30), (5, 198), (4, 61), (0, 30), (5, 200)] [(1, 72), (2, 19), (3, 31), (4, 192), (6, 72), (5, 75)] [(3, 12), (0, 51)] ... 这些元组中的每一个都是以(键,值)的格式创建的: 有七个键:0、1、2、3、4、5、6 预期输出是一个数据帧,其中每一列由键命名: import pandas as pd print(df)

我有几个元组的Python列表:

[(0, 61), (1, 30), (5, 198), (4, 61), (0, 30), (5, 200)]
[(1, 72), (2, 19), (3, 31), (4, 192), (6, 72), (5, 75)]
[(3, 12), (0, 51)]
...
这些元组中的每一个都是以
(键,值)
的格式创建的:

有七个键:0、1、2、3、4、5、6

预期输出是一个数据帧,其中每一列由键命名:

import pandas as pd
print(df)

0    1    2    3    4    5    6 
91   30   0    0    61   198  0
0    72   19   31   192  75   72
51   0    0    12   0    0    0
现在,我在概念上遇到的问题是,如果它们的键相同,如何添加几个元组“值”

我可以访问给定列表的这些值,例如

mylist = [(0, 61), (1, 30), (5, 198), (4, 61), (0, 30), (5, 200)]
keys =  [x[0] for x in mylist]

我不知道如何创建,例如,键:值对字典,我可以将其加载到熊猫数据帧中,我会:

  • 合并内部列表(将相同的键添加到一起)
  • 将集合从合并列表创建为集合列表(我将其与第一步相结合)
  • 制作数据帧
  • 更换
    NaN
    s

输出:

      0    1      2      3     4      5      6
0  91.0   30    0.0    0.0    61    398    0.0
1   0.0   72   19.0   31.0   192     75   72.0
2  81.0   40    0.0    0.0    21  21298    0.0
3   0.0  702  190.0  310.0  1092    705  702.0

以名称
tups

tups = [
    [(0, 61), (1, 30), (5, 198), (4, 61), (0, 30), (5, 200)],
    [(1, 72), (2, 19), (3, 31), (4, 192), (6, 72), (5, 75)],
    [(3, 12), (0, 51)]
]

选项0
使用
np.bincount
和疯狂地图、拉链和splats
这是因为
np.bincount
s前两个参数是位置数组和添加时使用的可选权重数组

pd.DataFrame(
    list(map(lambda t: np.bincount(*zip(*t)), tups))
).fillna(0, downcast='infer')

    0   1   2   3    4    5   6
0  91  30   0   0   61  398   0
1   0  72  19  31  192   75  72
2  51   0   0  12    0    0   0

选项1
在轴水平上使用理解和求和

pd.Series({
    (i, j, k): v
    for i, row in enumerate(tups)
    for k, (j, v) in enumerate(row)
}).sum(level=[0, 1]).unstack(fill_value=0)

    0   1   2   3    4    5   6
0  91  30   0   0   61  398   0
1   0  72  19  31  192   75  72
2  51   0   0  12    0    0   0

选项2
您可以在使用defaultdict的结果上使用
DataFrame
构造函数:

from collections import defaultdict

d = defaultdict(lambda: defaultdict(int))

for i, row in enumerate(tups):
    for j, v in row:
        d[j][i] += v

pd.DataFrame(d).fillna(0, downcast='infer')

    0   1   2   3    4    5   6
0  91  30   0   0   61  398   0
1   0  72  19  31  192   75  72
2  51   0   0  12    0    0   0

选项3
创建一个零数据帧并通过迭代进行更新

n, m = len(tups), max(j for row in tups for j, _ in row) + 1

df = pd.DataFrame(0, range(n), range(m))

for i, row in enumerate(tups):
    for j, v in row:
        df.at[i, j] += v

df

    0   1   2   3    4    5   6
0  91  30   0   0   61  398   0
1   0  72  19  31  192   75  72
2  51   0   0  12    0    0   0

您可以应用
groupby
先对每个元素按键求和,然后使用
pandas
转换为数据帧注意在求和之前必须先按键排序

import pandas as pd
from itertools import groupby

data = [
    [(0, 61), (1, 30), (5, 198), (4, 61), (0, 30), (5, 200)],
    [(1, 72), (2, 19), (3, 31), (4, 192), (6, 72), (5, 75)],
    [(0, 71), (1, 40), (5, 98), (4, 21), (0, 10), (5, 21200)],
    [(1, 702), (2, 190), (3, 310), (4, 1092), (6, 702), (5, 705)],
] # copying example from @PatrickArtnerz solution

def group_sum(data):
    """given list, return dictionary of summation based on initial key"""
    data_dict = {k: sum(v_[1] for v_ in v) for k, v in groupby(sorted(data, key=lambda x: x[0]), lambda x: x[0])}
    return data_dict

df = pd.DataFrame(list(map(group_sum, data))).fillna(0)

使用piRSquared的例子:

tups = [
    [(0, 61), (1, 30), (5, 198), (4, 61), (0, 30), (5, 200)],
    [(1, 72), (2, 19), (3, 31), (4, 192), (6, 72), (5, 75)],
    [(3, 12), (0, 51)]
]

#First build a dict for each row with unique keys.
data = [{f[0]:[] for f in e} for e in tups]
#add values to the dict as list which can capture multiple values.
[[data[k][e[0]].append(e[1]) for e in v] for k,v in enumerate(tups)]
#sum values for each key for each row.
data = [{k:sum(v) for k,v in e.items()} for e in data]
# build a df and fillna with 0
pd.DataFrame(data).fillna(0, downcast='infer')

Out[127]: 
    0   1   2   3    4    5   6
0  91  30   0   0   61  398   0
1   0  72  19  31  192   75  72
2  51   0   0  12    0    0   0

0从何而来?@chrisz 0在元组的上方,
(0,61)
我很欣赏这种感觉。就我个人而言,我更愿意给出一个答案。我在回答@Allen的答案时指出,
downcast='infer'
和生成的数据帧的大小存在一些问题。为什么会这样?另外,非常感谢您的全面回答!我认为这对帮助我和其他读者学习很有帮助:)谢谢你的回复。我感谢你的评论。然而,我注意到我自己的数据有问题;长度
len(tup)
最终略大于数据帧中的行数。你知道为什么会这样吗?可能是
tups
中存在导致此问题的空列表/元组…事实上,我似乎没有在
pd.DataFrame(data.fillna(0)
中看到此问题。行的#现在与
len(tups)
相同,但数据帧的格式似乎不正确。你知道为什么会这样吗?
import pandas as pd
from itertools import groupby

data = [
    [(0, 61), (1, 30), (5, 198), (4, 61), (0, 30), (5, 200)],
    [(1, 72), (2, 19), (3, 31), (4, 192), (6, 72), (5, 75)],
    [(0, 71), (1, 40), (5, 98), (4, 21), (0, 10), (5, 21200)],
    [(1, 702), (2, 190), (3, 310), (4, 1092), (6, 702), (5, 705)],
] # copying example from @PatrickArtnerz solution

def group_sum(data):
    """given list, return dictionary of summation based on initial key"""
    data_dict = {k: sum(v_[1] for v_ in v) for k, v in groupby(sorted(data, key=lambda x: x[0]), lambda x: x[0])}
    return data_dict

df = pd.DataFrame(list(map(group_sum, data))).fillna(0)
tups = [
    [(0, 61), (1, 30), (5, 198), (4, 61), (0, 30), (5, 200)],
    [(1, 72), (2, 19), (3, 31), (4, 192), (6, 72), (5, 75)],
    [(3, 12), (0, 51)]
]

#First build a dict for each row with unique keys.
data = [{f[0]:[] for f in e} for e in tups]
#add values to the dict as list which can capture multiple values.
[[data[k][e[0]].append(e[1]) for e in v] for k,v in enumerate(tups)]
#sum values for each key for each row.
data = [{k:sum(v) for k,v in e.items()} for e in data]
# build a df and fillna with 0
pd.DataFrame(data).fillna(0, downcast='infer')

Out[127]: 
    0   1   2   3    4    5   6
0  91  30   0   0   61  398   0
1   0  72  19  31  192   75  72
2  51   0   0  12    0    0   0