groupby with conditions并对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

首先需要使用名称和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(>gt>gt>gt>不是违规者(例如:adam(

    ii.(所有其他id组合>gt>gt>违反者(前:凯文和安杰洛(

最终期望的数据帧:

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

我这么做的目的:

首先,我使用名称和id进行分组,并为每个组合获取计数(但此方法不会返回上面显示的数据帧。(

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

在第二部分中,我只知道如果名称同时包含id(90和91(,如何识别违规者。我不知道如何将上述条件赋予已识别的vioalators。

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

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

让我们尝试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

详细信息:

使用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

获得groupby计数后,为什么不过滤掉ID=90的行并计数<5,然后继续你的逻辑?您可以在删除之前取一组名称,并在冲突中将nas填充为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)

您还可以尝试在分组步骤后对数据帧进行透视:

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)

最新更新