我有以下熊猫数据框。
import pandas as pd
data = {'id_a': [1, 1, 1, 2, 2, 2, 3, 4], 'name_a': ['a', 'a', 'a', 'b', 'b', 'b', 'c', 'd'],
'id_b': [5, 6, 7, 8, 9, 10, 11, 11], 'name_b': ['e', 'f', 'g', 'h', 'i', 'j', 'k', 'k'],
'similar': [1, 1, 1, 1, 1, 0, 1, 1], 'metric': [.5, 1, .8, .7, .2, .9, .8, .9]}
df = pd.DataFrame(data)
print(df)
⠀
id_a name_a id_b name_b similar metric
--- ------ -------- ------ -------- --------- --------
0 1 a 5 e 1 0.5
1 1 a 6 f 1 1.0
2 1 a 7 g 1 0.8
3 2 b 8 h 1 0.7
4 2 b 9 i 1 0.2
5 2 b 10 j 0 0.9
6 3 c 11 k 1 0.8
7 4 d 11 k 1 0.9
在此表中,组A的ID链接到组B的ID(基于列similar
)。
但是我需要每个组的唯一ID才能对应于另一个组的一个ID。
在每个组具有相同ID的行中,我需要选择metric
列最大的行。
例如,我有三行,id_a
==2。在这三行中,只有两行的列similar
等于1。
在这两行中,一行的metric
列值为0.7,第二行的值为0.2。
仅对列similar
为0.7(因为最大值)的行保留列metric
= 1的值,对于第二行,我将列{的值{1}} =0。
也就是说,我需要以下数据框:
similar
⠀
output_data = {'id_a': [1, 1, 1, 2, 2, 2, 3, 4], 'name_a': ['a', 'a', 'a', 'b', 'b', 'b', 'c', 'd'],
'id_b': [5, 6, 7, 8, 9, 10, 11, 11], 'name_b': ['e', 'f', 'g', 'h', 'i', 'j', 'k', 'k'],
'similar': [0, 1, 0, 1, 0, 0, 0, 1], 'metric': [.5, 1, .8, .7, .2, .9, .8, .9]}
output_df = pd.DataFrame(output_data)
print(output_df)
问题:如何使用Python实现此操作(因为我的研究未给出任何结果)?
答案 0 :(得分:2)
我不确定您如何为机构处理id_a == 3
的情况,但是我认为这是您想要的。只需从每个组(按id_a
分组)中获取最大索引,然后在重置similar
列之后,将那些最大索引重置为1。
max_vals = df.groupby('id_a').apply(lambda grp: grp.loc[grp['similar'] == 1, 'metric'].idxmax())
df['similar'] = 0
df.loc[max_vals, 'similar'] = 1
>>> df
id_a name_a id_b name_b similar metric
0 1 a 5 e 0 0.5
1 1 a 6 f 1 1.0
2 1 a 7 g 0 0.8
3 2 b 8 h 1 0.7
4 2 b 9 i 0 0.2
5 2 b 10 j 0 0.9
6 3 c 11 k 1 0.8
7 4 d 11 k 1 0.9
编辑:查看有关为什么输出与第6行不完全匹配的注释。
答案 1 :(得分:2)
IIUC,您可以这样做:
# find the indices of the maximum by id_a
keep_a = df[df.similar.eq(1)].groupby('id_a').filter(lambda x: len(x) > 1).groupby('id_a').metric.idxmax()
# find the indices of the maximum by id_b
keep_b = df[df.similar.eq(1)].groupby('id_b').filter(lambda x: len(x) > 1).groupby('id_b').metric.idxmax()
# create mask False if is in set of maximum
mask = ~df.index.isin(set(keep_a) | set(keep_b))
# set values using mask
df.loc[mask, 'similar'] = 0
print(df)
输出
id_a name_a id_b name_b similar metric
0 1 a 5 e 0 0.5
1 1 a 6 f 1 1.0
2 1 a 7 g 0 0.8
3 2 b 8 h 1 0.7
4 2 b 9 i 0 0.2
5 2 b 10 j 0 0.9
6 3 c 11 k 0 0.8
7 4 d 11 k 1 0.9
答案 2 :(得分:2)
Series.mask
将metric
的值转换为NaN
的{{1}},使其永远不会是最大值,因此结果为1。
Series.shift
+ Series.cumsum
+ Series.all
,以便在similar == 0
或id_a
中有连续值的情况下进行分组。请记住,对于N个ID来说就这么简单。
使用id_b
创建一个分组最大的序列,并将其与groupby.transform
系列进行比较,以获得布尔序列,可以将Series.astype
转换为{{1 }}或Metric
1
输出
0
组的详细信息
df2=df.copy()
#discarding similar == 0 as a maximum candidate in the groups
df2['metric']=df2['metric'].mask(df2['similar'].eq(0))
#creating groups depend on id_a and id_b
ids=df2[['id_a','id_b']]
groups=ids.ne(ids.shift()).all(axis=1).cumsum()
#checking the maximum per group and converting to integer
df['similar']=df['metric'].eq(df2.groupby(groups).metric.transform('max')).astype(int)
print(df)
答案 3 :(得分:2)
在listcomp中使用groupby idxmax
,isin
和2个groupby并传递到np.array
。最后,在all
上呼叫astype
和np.array
df1 = df[df.similar.eq(1)]
df['similar'] = np.array([df.index.isin(df1.groupby(col).metric.idxmax())
for col in ['id_a', 'id_b']]).all(0).astype(int)
Out[132]:
id_a name_a id_b name_b similar metric
0 1 a 5 e 0 0.5
1 1 a 6 f 1 1.0
2 1 a 7 g 0 0.8
3 2 b 8 h 1 0.7
4 2 b 9 i 0 0.2
5 2 b 10 j 0 0.9
6 3 c 11 k 0 0.8
7 4 d 11 k 1 0.9
答案 4 :(得分:1)
仅使用向量化方法的解决方案。
m1
:向量,每个组具有max
个值,similar == 1
m2
:其中similar == 1
m3
:具有max
值和similar == 1
m1 = df.query('similar == 1').groupby('id_a')['metric'].transform('max')
m2 = df['similar'].eq(1)
m3 = df.loc[m2, 'metric'].eq(m1)
df.loc[m3[~m3].index, 'similar'] = 0
id_a name_a id_b name_b similar metric
0 1 a 5 e 0 0.50
1 1 a 6 f 1 1.00
2 1 a 7 g 0 0.80
3 2 b 8 h 1 0.70
4 2 b 9 i 0 0.20
5 2 b 10 j 0 0.90
6 3 c 11 k 1 0.80
7 4 d 11 k 1 0.90