pandas 获取 Dataframe 中组中每个元素的百分比

3xiyfsfu  于 2023-02-07  发布在  其他
关注(0)|答案(4)|浏览(223)

给定如下 Dataframe :

id  column1   column2   column3   column4    columns5
1      a         b        a          b           x
2      b         a        c          b           y
3      c         b        a          c           x

考虑到这些群体:

group_1 = [a,b,c]
group_2 = [x,y,z]

如何获得此输出:

%_a        %_b       %_c     %_x        %_y       %_z
0.3333   0.4167     0.25     0.667      0.333      0

因为:

% of elements of group_1:  a=4/12, b=5/12, c=3/12
% of elements of group_2:  x=2/3, y=1/3, z=0
ki1q1bka

ki1q1bka1#

下面是df.stack的一种方法:

group_1 = ['a','b','c']
group_2 = ['x','y','z']

s = df.stack()

res = (pd
       .concat(
           [s[s.isin(g)].value_counts(normalize=True)
            .reindex(g).fillna(0) 
            for g in [group_1, group_2]]
           )
       .to_frame().T.add_prefix('%_')
       )

res

        %_a       %_b   %_c       %_x       %_y  %_z
0  0.333333  0.416667  0.25  0.666667  0.333333  0.0
    • 说明**
  • 首先,我们使用df.stackdf转换为pd.Series
  • 现在,对于每个组,我们只想获取属于该特定组的值(使用Series.isin),并将normalize参数设置为True,将Series.value_counts应用于此选择。
  • 接下来,我们链接Series.reindex以重新添加组中未出现在选择中的任何值(即group_1中的z);我们通过使用Series.fillna为任何这样的缺失值提供值0
  • 我们使用列表解析将此逻辑应用于两个组,并将结果用作pd.concat的输入以返回一个Series
  • 最后,我们将Series转换为dfSeries.to_frame),将其转置(df.T),并向列添加前缀(df.add_prefix)。
xnifntxz

xnifntxz2#

您可以为此使用布尔掩码。例如:

df.isin(group_1)

将为您提供一个布尔掩码,其中列表group_1中DataFrame的值为True,其余为False。然后计算为True的值的数量就像使用.sum()方法两次或.values.sum()一样简单(即转换为numpy数组,然后对真值求和)。
以同样的方式,您可以迭代通过组的元素,并使用布尔掩码来过滤单个值,例如。

for i in group_1:
    print(f"Number of {i}= {(df==i).values.sum()}")

对于解决方案,我将把组放在字典中,然后遍历字典:

groups = {'group1': group_1, 'group2': group_2 }
results = {}
for group_name, group in groups.items():
    count_group = df.isin(group).values.sum()
    results[group_name] = {}
    for val in group:
        count_value = (df==val).values.sum()
        results[group_name][val] = count_value/count_group
print(results)
6tdlim6h

6tdlim6h3#

下面是关于meltvalue_counts的命题:

g1 = df.isin(group_1).sum().sum()
g2 = df.isin(group_2).sum().sum()
​
d = {**{k:g1 for k in group_1}, **{k:g2 for k in group_2}}
​
out = (
        df
          .set_index("id").melt()
           ["value"].value_counts().to_frame()
          .join(pd.Series(d).rename("c"), how="outer").fillna(0)
          .assign(temp_col= lambda x: x.pop("value").div(x.pop("c")))
          .T.sort_index(axis=1).add_prefix("%_").reset_index(drop=True)

      )

输出:

print(out)

        %_a       %_b   %_c       %_x       %_y  %_z
0  0.333333  0.416667  0.25  0.666667  0.333333  0.0
093gszye

093gszye4#

如果group_1group_2的元素不能在同一列中共存,可能的解决方案是,基于numpy

def get_percs(df, group, cols):
    size = df.iloc[:,cols].values.size
    return np.sum(
        np.sum(df.iloc[:,cols].values ==
               np.array(group)[:,None][:,None], axis=2),
        axis=1) / size

get_percs(df, group_1, range(1,5)), get_percs(df, group_2, range(5,6))

输出:

(array([0.33333333, 0.41666667, 0.25      ]),
 array([0.66666667, 0.33333333, 0.        ]))

如果要求输出为 Dataframe :

pd.concat([pd.DataFrame(get_percs(df, g[0], g[1]).reshape(1,-1), 
                        columns=[f'%_{x}' for x in g[0]]) 
           for g in zip([group_1, group_2], [range(1,5), range(5,6)])], axis=1)

输出:

%_a       %_b   %_c       %_x       %_y  %_z
0  0.333333  0.416667  0.25  0.666667  0.333333  0.0

相关问题