groupby 条件和分类 python

groupby with conditions and classify python

我有包含 2 列(名称和 ID)的数据框。有成千上万的名字。但是每个名字,只有两个id(90和91,所以在id列中只包含90和91)。

样本数据帧如下。

name    id
kevin   90
kevin   91
kevin   90
kevin   90
John    90
John    90
John    90
John    90
John    90
kevin   90
kevin   90
kevin   91
kevin   91

首先需要使用 name 和 id 列 groupby获取每个组合的计数

预期输出:

name    id  count
kevin   90  13
        91  2
elly    91  15
john    90  6
adam    90  3
        91  20
anjelo  90  12
        91  19

然后需要使用以下条件对违规进行分类。

  1. 一个名字只包含一个id(90或91),不违规(例如elly 和 john 没有 违规者)。

  2. 一个名字包含两个id,

    i.) 90:小于5和91:任意数(大于0)>>>>>>>> 不是违规者(例如:亚当)

    ii.) 所有其他 id 组合>>>>> Violator(例如:kevin 和 anjelo)

最终预期的数据帧:

name    violation
kevin     1
elly      0
john      0
adam      0
anjelo    1

我的尝试是为了:

首先我使用 name 和 id 进行分组并获取每个组合的计数(但此方法不 return 上面显示的数据框。)

df.groupby(['name', 'id']).size().reset_index(name='counts')

在第二部分,我只知道如果名称包含两个id(90和91),如何识别违规者。我不知道如何给已识别的违规者提供上述条件。

x = df.groupby('name').id.unique().reset_index()
x['Violation'] = x.id.apply(lambda x: 1 if (90, 91) in zip(x, x[1:]) else 0)
x.drop('id', 1, inplace=True)
x

非常感谢您的支持!!!!!!!!!!!!!!!!

获得 groupby 计数后,为什么不过滤掉 ID=90 且计数<5 的行并继续您的逻辑?您可以在删除之前取一组名称,最后将其与您的最终输出合并,方法是将 nas 填入 violations 为 0。

import numpy as np
g=df.groupby(['name','id']).size().to_frame('count').reset_index()#Groupby to get dataframe with count

#Allocate viloation
g['violation']=np.where((~g.name.duplicated(keep=False))|(g.id.eq(90)&g['count'].le(5)|g.id.eq(91)&g['count'].gt(0)),0,1)
print(g)

让我们尝试 crosstab 和布尔掩码来定位违规者:

# frequency table
s = pd.crosstab(df['name'], df['id'])

m1 = s.ne(0).sum(1).eq(1) # condition 1
m2 = ~m1 & s[90].lt(5) & s[91].gt(0) # condition 2
out = (~m1 & ~m2).view('i1').to_frame('violator') # violators

详情:

计算频率 table 使用 crosstab:

print(s)
        90  91
adam     3  20
anjelo  12  19
elly     0  15
john     6   0
kevin   13   2

创建表示条件的布尔掩码 名称仅包含一个 ID(90 或 91):

print(m1)
name
adam      False
anjelo    False
elly       True # -> Non violator
john       True # -> Non violator
kevin     False
dtype: bool

创建表示条件的布尔掩码 名称包含两个 ID, 90 的值小于 5 而 91 的值大于 0:

print(m2)
name
adam       True # -> Non violator
anjelo    False
elly      False
john      False
kevin     False
dtype: bool

结合condition 1condition 2得到违规者:

print(out)
         violator
name             
adam            0
anjelo          1
elly            0
john            0
kevin           1

您也可以尝试在分组步骤后旋转数据框:

import pandas as pd    
pv=pd.pivot_table(df, values = 'counts', index=['name'], columns = 'id').reset_index().fillna(0)
pv.columns = pv.columns.map(str)

之后您可以应用逻辑来获取违规标志:

import numpy as np
pv['violation'] = np.where((pv['90']==0) | (pv['91']==0) | (pv['90']<5) & (pv['91']>0),0,1)