我有一个包含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
然后需要使用以下条件对违规行为进行分类。
一个名称只包含一个id(90或91(,它是而不是违反的行为(例如elly和john不是违反者(。
名称包含两个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 1
和condition 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)