因此,我认为在给出数据框的情况下,可以最好地将这个问题可视化:
val_1 true_val ID label
-0.0127894447 0.0 1 A
0.9604560385 1.0 2 A
0.0001271985 0.0 3 A
0.0007419337 0.0 3 B
0.3420448566 0.0 2 B
0.1322384726 1.0 4 B
所以我想得到的是:
label ID_val_1_second_highest ID_true_val_highest
A 3 2
B 4 4
我想获取具有val_1的第二个最大值和true_val的第二个最大值的ID(始终为1.0),然后为每个标签返回两个对应的ID。
任何人都知道如何执行此操作?我尝试过:
result_at_one = result.set_index('ID')。groupby('label')。idxmax()
这可以为我两个都提供最大值,但是我只希望真正标签的最大值,而让val_1变量获得第二个/第三个等最大值。
有人将此链接作为答案: Pandas: Get N largest values and insert NaN values if there are no elements
但是,如果使用该方法,则需要按标签分组。因此,在这种情况下,输出将变为:
label true_id top1_id_val_1 top2_id_val_1 top3_id_val_1
A 2 2 3 1
B 4 2 4 3
有人知道怎么做吗?
答案 0 :(得分:3)
您可以将groupby
与自定义的apply
函数结合使用以实现所需的结果。
def sorted_maximums(group, nlargest, upto=False):
# Get the largest IDs in the current group
largest_ids = group.nlargest(nlargest, "val_1")["ID"]
index = ["val_1_ID_rank_{}".format(i) for i in range(1, nlargest+1)]
# Drop data if we're only interested in the nlargest value
# and none of the IDs leading up to it
if upto is False:
largest_ids = largest_ids.iloc[nlargest-1:]
index = index[-1:]
# Get the ID at the max "true_val"
true_val_max = group.at[group["true_val"].idxmax(), "ID"]
index += ["ID_true_val_highest"]
# Combine our IDs based on val_1 and our ID based on true_val
data = [*largest_ids, true_val_max]
return pd.Series(data, index=index)
df.groupby("label").apply(sorted_maximums, nlargest=2, upto=False).reset_index()
label val_1_ID_rank_2 ID_true_val_highest
0 A 3 2
1 B 4 4
df.groupby("label").apply(sorted_maximums, nlargest=2, upto=True).reset_index()
label val_1_ID_rank_1 val_1_ID_rank_2 ID_true_val_highest
0 A 2 3 2
1 B 2 4 4
由于我不确定您是否有兴趣获取第二大的ID(@ val_1),还是一次获得第一,第二和第三高的ID @ val_1,因此我不确定这两种方法。更改upto = True将执行后者,而upto = False将会执行前者,并且仅使您获得最高,第一,第二或第三ID @ val_1
答案 1 :(得分:3)
您可以将其分为几个阶段:
# grouping is relatively inexpensive :
grouping = df.groupby("label")
# get second highest val
id_val = grouping.nth(-1)["ID"].rename("ID_val_1_second_highest")
#get highest true val
# you could also do df.true_val.eq(grouping.true_val.transform('max'))
# since we know the highest is 1, I just jumped into it
true_val = (df.loc[df.true_val == 1, ["ID", "label"]]
.set_index("label")
.rename( columns={"ID": "ID_true_val_highest"}))
# merge to get output :
pd.concat([id_val, true_val], axis=1,).reset_index()
label ID_val_1_second_highest ID_true_val_highest
0 A 3 2
1 B 4 4
答案 2 :(得分:1)
尝试了几种方法(即排序+排序+融合,旋转,使用自定义功能的分组方式)后,我得出的结论是,扩展的分组方式是您最好的解决方案。 (最好用于此类特殊情况):
records = []
# Iterate through your groupby objects
for group_label, group_df in df[["label","ID","val_1"]].groupby("label"):
# get ranked indices
rank_idx = group_df["val_1"].rank()
# extract individual attributes
ID_true_val_highest = group_df.loc[rank.rank_idx[1], "ID"]
ID_val_1_second_highest = group_df.loc[rank.rank_idx[2], "ID"]
# store your observations
rec = {
"label":group_label,
"ID_true_val_highest":ID_true_val_highest,
"ID_val_1_second_highest":ID_val_1_second_highest,
}
records.append(rec)
# make into a dataframe
pd.DataFrame.from_records(records)
label ID_true_val_highest ID_val_1_second_highest
0 A 2.0 3.0
1 B 2.0 4.0