如何在某个特定ID的熊猫列中获得第二高的价值?

时间:2020-09-15 16:30:24

标签: python pandas

因此,我认为在给出数据框的情况下,可以最好地将这个问题可视化:

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

有人知道怎么做吗?

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
相关问题