使用熊猫计算具有特定值的列的份额

时间:2019-07-17 20:51:49

标签: python pandas dataframe group-by pandas-groupby

我有一个包含两列的DataFrame:键和值。我想构造一个新的列,如下所示。对于每个键,请从该键的总值中计算每个值的频率。

我有实现它的代码,但是我怀疑在熊猫中必须有一种更简单的方法来做到这一点。这是一个示例:

def fun(sd):
    uniqueValuesList = list(sd.drop_duplicates().dropna())
    if len(uniqueValuesList)==0:
        return pd.Series([0]*sd.shape[0], index=sd.index)
    elif len(uniqueValuesList)==1:
        return pd.Series([1]*sd.shape[0], index=sd.index)
    else:
        valuesList = list(sd)
        valuesArr = np.array(valuesList)        
        stackedValuesDf = pd.DataFrame([valuesArr]*len(valuesArr))
        boolDf = stackedValuesDf==valuesList
        frac = boolDf.sum() / boolDf.shape[0]
        return frac

keys =   ['1', '1', '1', '2', '3']
values = ['a', 'b', 'b', 'c', np.nan]
df = pd.DataFrame([keys, values]).T
df.columns = ['keys', 'values']
print(df.groupby('keys').values.apply(fun))

这将提供所需的输出:

0    0.333333
1    0.666667
2    0.666667
3    1.000000
4    0.000000

也就是说,对于键'1''a'出现一次,而'b'出现两次,因此它们分别得到0.33和0.67。对于'2',有一个单例键,所以它得到1。对于'3',没有键,所以它得到0。

实现这一目标的更简单的熊猫方法是什么?

1 个答案:

答案 0 :(得分:1)

您不能transform pd.Series.value_counts,因此可以对size使用两个变换:

m = df['values'].notnull()

df.loc[m, 'per'] = (df.loc[m].groupby(['keys', 'values'])['values'].transform('size')
                     / df.groupby('keys')['values'].transform('size'))

df['per'] = df['per'].fillna(0)

#  keys values       per
#0    1      a  0.333333
#1    1      b  0.666667
#2    1      b  0.666667
#3    2      c  1.000000
#4    3    NaN  0.000000

或者,通过合并:

df1 = (df.groupby('keys')['values']
         .apply(pd.Series.value_counts, normalize=True)
         .to_frame('per'))
df1.index.names=['keys', 'values']

df = df.merge(df1.reset_index(), how='left')
df['per'] = df['per'].fillna(0)