首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >熊猫组根据如何在列上聚合并转换成每个单元格都是字典的矩阵。

熊猫组根据如何在列上聚合并转换成每个单元格都是字典的矩阵。
EN

Stack Overflow用户
提问于 2018-05-16 16:26:18
回答 2查看 573关注 0票数 1

我有df

代码语言:javascript
复制
key    amount    code    year_month
CHQ    100       1000    201701
EFT    200       1000    201701
CHQ    300       2000    201702
CHQ    400       2000    201702
EFT    500       3000    201703
EFT    600       4000    201703

我喜欢groupby codeyear_month,然后在字典中对key进行聚合计数,因此结果如下

代码语言:javascript
复制
                   key
code year_month
1000 201701        {'CHQ':1, 'EFT':1}
2000 201702        {'CHQ':2, 'EFT':0}
3000 201703        {'CHQ':0, 'EFT':2}

然后将上述df转换为以code值作为行标签、year_month值作为列标签的矩阵,并在第0行和第0列上进行聚合,例如,对于所有codeyear_month(1,1)count(1,2)201701进行count之和。

代码语言:javascript
复制
     0          1                  2                      3                 4 
 0   -1         0                201701                 201702            201703
 1   0    {'CHQ':3,'EFT':3}  {'CHQ':1,'EFT':1}    {'CHQ':2,'EFT':0}  {'CHQ':0,'EFT':2}              
 2   1000 {'CHQ':1,'EFT':1}  {'CHQ':1,'EFT':1}    {'CHQ':0,'EFT':0}  {'CHQ':0,'EFT':0}                    
 3   2000 {'CHQ':2,'EFT':0}  {'CHQ':0,'EFT':0}    {'CHQ':2,'EFT':0}  {'CHQ':0,'EFT':0}
 4   3000 {'CHQ':0,'EFT':2}  {'CHQ':0,'EFT':0}    {'CHQ':0,'EFT':0}  {'CHQ':0,'EFT':2}        
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-05-16 16:52:14

defaultdict

代码语言:javascript
复制
from collections import defaultdict

a = dict.fromkeys(df.key.unique(), 0)
b = defaultdict(lambda:defaultdict(lambda:a))

for t in df.itertuples():
    b[t.year_month][t.code][t.key] += 1
    b['All'][t.code][t.key] += 1
    b[t.year_month]['All'][t.key] += 1

idx = df.code.unique().tolist() + ['All']
idx = pd.CategoricalIndex(idx, idx, ordered=True)

col = df.year_month.unique().tolist() + ['All']
col = pd.CategoricalIndex(col, col, ordered=True)

m = pd.DataFrame(b, idx, col)
m = m.mask(m.isna(), a)

m

                    201701                201702                201703                   All
1000  {'CHQ': 9, 'EFT': 9}  {'CHQ': 9, 'EFT': 9}  {'CHQ': 9, 'EFT': 9}  {'CHQ': 9, 'EFT': 9}
2000  {'CHQ': 9, 'EFT': 9}  {'CHQ': 9, 'EFT': 9}  {'CHQ': 9, 'EFT': 9}  {'CHQ': 9, 'EFT': 9}
3000  {'CHQ': 9, 'EFT': 9}  {'CHQ': 9, 'EFT': 9}  {'CHQ': 9, 'EFT': 9}  {'CHQ': 9, 'EFT': 9}
4000  {'CHQ': 9, 'EFT': 9}  {'CHQ': 9, 'EFT': 9}  {'CHQ': 9, 'EFT': 9}  {'CHQ': 9, 'EFT': 9}
All   {'CHQ': 9, 'EFT': 9}  {'CHQ': 9, 'EFT': 9}  {'CHQ': 9, 'EFT': 9}  {'CHQ': 9, 'EFT': 9}

appendconcat求和

代码语言:javascript
复制
d = df.groupby(['code', 'year_month', 'key']).size().unstack([1, 2], fill_value=0)
d = d.reindex(columns=pd.MultiIndex.from_product(d.columns.levels), fill_value=0)

def add_level(d, k):
    return pd.concat([d], keys=[k], axis=1)

m = d.join(d.sum(1, level=1).pipe(add_level, k='All')).pipe(
    lambda d: d.append(d.sum().rename('All'))
)

m.groupby(axis=1, level=0).apply(lambda x: pd.Series(x.xs(x.name, 1).to_dict('i')))

                    201701                201702                201703                   All
1000  {'CHQ': 1, 'EFT': 1}  {'CHQ': 0, 'EFT': 0}  {'CHQ': 0, 'EFT': 0}  {'CHQ': 1, 'EFT': 1}
2000  {'CHQ': 0, 'EFT': 0}  {'CHQ': 2, 'EFT': 0}  {'CHQ': 0, 'EFT': 0}  {'CHQ': 2, 'EFT': 0}
3000  {'CHQ': 0, 'EFT': 0}  {'CHQ': 0, 'EFT': 0}  {'CHQ': 0, 'EFT': 1}  {'CHQ': 0, 'EFT': 1}
4000  {'CHQ': 0, 'EFT': 0}  {'CHQ': 0, 'EFT': 0}  {'CHQ': 0, 'EFT': 1}  {'CHQ': 0, 'EFT': 1}
All   {'CHQ': 1, 'EFT': 1}  {'CHQ': 2, 'EFT': 0}  {'CHQ': 0, 'EFT': 2}  {'CHQ': 3, 'EFT': 3}

交替to_dict

代码语言:javascript
复制
pd.DataFrame({
    j: {
        i: m.loc[i, j].to_dict()
        for i in m.index
    } for j in m.columns.levels[0]
})

旧答案

代码语言:javascript
复制
import pandas as pd
from collections import Counter

d = df.groupby(['code', 'year_month', 'key']).size().unstack(fill_value=0).assign(
    key=lambda d: d.to_dict('r')
)[['key']].reset_index().rename_axis(None, 1).assign(key=lambda d: list(map(Counter, d.key)))
d

   code  year_month                   key
0  1000      201701  {'CHQ': 1, 'EFT': 1}
1  2000      201702  {'CHQ': 2, 'EFT': 0}
2  3000      201703  {'CHQ': 0, 'EFT': 1}
3  4000      201703  {'CHQ': 0, 'EFT': 1}

然后

代码语言:javascript
复制
fv = Counter(dict.fromkeys(df.key.unique(), 0))
d2 = d.pivot_table(
    'key', 'code', 'year_month', 'sum',
    margins=True
).pipe(lambda d: d.mask(d.isna(), fv))
d2

year_month                201701                201702                201703                   All
code                                                                                              
1000        {'CHQ': 1, 'EFT': 1}  {'CHQ': 0, 'EFT': 0}  {'CHQ': 0, 'EFT': 0}  {'CHQ': 1, 'EFT': 1}
2000        {'CHQ': 0, 'EFT': 0}  {'CHQ': 2, 'EFT': 0}  {'CHQ': 0, 'EFT': 0}  {'CHQ': 2, 'EFT': 0}
3000        {'CHQ': 0, 'EFT': 0}  {'CHQ': 0, 'EFT': 0}  {'CHQ': 0, 'EFT': 1}  {'CHQ': 0, 'EFT': 1}
4000        {'CHQ': 0, 'EFT': 0}  {'CHQ': 0, 'EFT': 0}  {'CHQ': 0, 'EFT': 1}  {'CHQ': 0, 'EFT': 1}
All         {'CHQ': 1, 'EFT': 1}  {'CHQ': 2, 'EFT': 0}            {'EFT': 2}  {'CHQ': 3, 'EFT': 3}

我们可以破译一些东西让事情开始运作。我对此感觉不太好,但也许这足以满足你的需要。

使用Counter.update在位置上更改对象

代码语言:javascript
复制
d2.applymap(lambda x: x.update(fv));

d2

year_month                201701                201702                201703                   All
code                                                                                              
1000        {'CHQ': 1, 'EFT': 1}  {'CHQ': 0, 'EFT': 0}  {'CHQ': 0, 'EFT': 0}  {'CHQ': 1, 'EFT': 1}
2000        {'CHQ': 0, 'EFT': 0}  {'CHQ': 2, 'EFT': 0}  {'CHQ': 0, 'EFT': 0}  {'CHQ': 2, 'EFT': 0}
3000        {'CHQ': 0, 'EFT': 0}  {'CHQ': 0, 'EFT': 0}  {'CHQ': 0, 'EFT': 1}  {'CHQ': 0, 'EFT': 1}
4000        {'CHQ': 0, 'EFT': 0}  {'CHQ': 0, 'EFT': 0}  {'CHQ': 0, 'EFT': 1}  {'CHQ': 0, 'EFT': 1}
All         {'CHQ': 1, 'EFT': 1}  {'CHQ': 2, 'EFT': 0}  {'EFT': 2, 'CHQ': 0}  {'CHQ': 3, 'EFT': 3}
票数 1
EN

Stack Overflow用户

发布于 2018-05-17 18:00:46

如果我说对了的话,这就是我的想法:

代码语言:javascript
复制
df_tmp = (df.groupby(['code', 'year_month'])['key']
           .agg(lambda x: (Counter(x),))
           .to_frame()
           .reset_index()
          )

# Pivot 
df_pivot = pd.pivot_table(df_tmp, index='code', columns='year_month', values='key', aggfunc=np.sum)
# Filling the gaps
df_final = df_pivot.apply(lambda x: [v[0] if v is not None else Counter(dict.fromkeys(df.key, 0)) for v in x ])

请注意,(Counter(x),)函数中的这个tupeling“agg”是一个小的变通方法,因为熊猫似乎不喜欢处理对象。但是,无论如何,这将在最后的apply调用中被打开。

由于您有Counter实例,所以可以对列/行进行求和,并获得正确的结果:

代码语言:javascript
复制
df_final.sum(1)

复制粘贴示例

代码语言:javascript
复制
from io import StringIO

import pandas as pd
import numpy as np

from collections import Counter

data = """
key    amount    code    year_month
CHQ    100       1000    201701
EFT    200       1000    201701
EFT    200       1000    201702
EFT    200       1000    201702
EFT    200       1000    201702
EFT    200       1000    201702
EFT    200       1000    201702
CHQ    300       2000    201702
CHQ    400       2000    201702
EFT    500       3000    201703
EFT    600       4000    201703
"""

df = pd.read_csv(StringIO(data), sep='\s+')

df_tmp = (df.groupby(['code', 'year_month'])['key']
           .agg(lambda x: (Counter(x),))
           .to_frame()
           .reset_index()
          )

# Pivot 
df_pivot = pd.pivot_table(df_tmp, index='code', columns='year_month', values='key', aggfunc=np.sum)
# Filling in the gaps 
df_final = df_pivot.apply(lambda x: [v[0] if v is not None else Counter(dict.fromkeys(df.key, 0)) for v in x ])
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50375813

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档