我的数据如下:
ID my_val db_val
a X X
a X X
a Y X
b X Y
b Y Y
b Y Y
c Z X
c X X
c Z X
预期结果 :
ID my_val db match
a X:2;Y:1 X full_match
b Y:2;X:1 Y full_match
c z:2;X:1 X partial_match
full_match是当db_val匹配最丰富的my_val时,partial_match是db_val在其他值中但与前一个值不匹配的时候。
我当前的方法包括按ID分组,然后将值计数到单独的列中,然后连接值及其计数,然后将每个ID的所有值聚合为一行。
这是我聚合列的方式:
def all_hits_aggregate_df(df, columns=['my_val']):
grouped = data.groupby('ID')
l=[]
for c in columns:
res = grouped[c].value_counts(ascending=False, normalize=False).to_frame('count_'+c).reset_index(level=1)
res[c] = res[c].astype(str) +':'+ res['count_'+c].astype(str)
l.append(res.groupby('ID').agg(lambda x: ';'.join(x)))
return reduce(lambda x, y: pd.merge(x, y, on = 'ID'), l)
对于比较阶段,我遍历每一行并将my_val列解析为列表然后进行比较。
我确信我进行比较步骤的方式非常低效但我不确定如何在聚合之前执行此操作以避免在此过程中稍后解析生成的字符串。
我们可以通过ID来groupby
DataFrame,然后使用my_val
计算value_counts
值并使用to_json
转换为json,这在格式化方面有一些小变化,它们为我们提供了所请求的格式(我们只需要删除大括号和引号并替换逗号用分号)。在分组数据上,我们还采用first
(并且可能是每个ID
唯一的一个)db_val
值并计算匹配百分比(超过50%将给我们full_match
,0-50%是partial_match
,0%是no_match
):
df['match'] = df['my_val']==df['db_val']
z = (df
.groupby('ID')
.agg({'my_val': lambda x: x.value_counts().to_json(),
'db_val': 'first',
'match': 'mean'})
).reset_index()
z['my_val'] = z['my_val'].str.replace('[{"}]','').str.replace(',',';')
z['match'] = np.select(
[z['match'] > 0.5, z['match'] > 0],
['full_match', 'partial_match'], 'no_match')
print(z)
输出:
ID my_val db_val match
0 a X:2;Y:1 X full_match
1 b Y:2;X:1 Y full_match
2 c Z:2;X:1 X partial_match
这应该给你你想要的第一部分:
df['equal'] = df.my_val == df.db_val
df2 = pd.DataFrame()
df2['my_val'] = df.groupby('ID')['my_val'].sum()
df2['db'] = df.groupby('ID')['db_val'].unique()
df2['match_val'] = df.groupby('ID')['equal'].sum()
df2['match'] = ''
df2.loc[df2.match_val/len(df2.my_val) > 0.5, 'match'] = 'full_match'
df2.loc[df2.match_val/len(df2.my_val) <= 0.5, 'match'] = 'partial_match'
df2.loc[df2.match_val/len(df2.my_val) == 0, 'match'] = 'no_match'
df2 = df2.drop(columns = 'match_val')
print(df2)
my_val db match
ID
a XXY [X] full_match
b XYY [Y] full_match
c ZXZ [X] partial_match