【问题标题】:Drop non-unique values in a range of columns based on a condition from a different range of columns根据来自不同列范围的条件删除列范围中的非唯一值
【发布时间】:2022-11-21 06:42:24
【问题描述】:

这是df的一小部分。

在这种情况下,我需要映射 3 个 y 值:0.93388397.6583301.650013

我有这个df

      x  y1  y2         y3         y4          d1  d2         d3         d4
23  5.3 NaN NaN   0.933883        NaN         NaN NaN   0.174866        NaN
25  5.3 NaN NaN        NaN  97.658330         NaN NaN        NaN   0.038670
26  5.3 NaN NaN   1.650013        NaN         NaN NaN   0.541264        NaN
29  5.3 NaN NaN  97.658330        NaN         NaN NaN  96.549581        NaN
30  5.3 NaN NaN        NaN   1.650013         NaN NaN        NaN  96.046987

每列不超过一个这些值,我已经删除了重复项。

我需要的:

我不能在多个列中具有相同的值。

选择删除哪一行的条件如下所示例子:

y3y4 列中有97.658330。因为对于该值,d3(96.549581) 大于d4(0.038670),所以删除行29

y3y4 列中有1.650013。由于d4(96.046987) 大于d3(0.541264),因此删除行30

输出:

      x  y1  y2         y3         y4          d1  d2         d3         d4
23  5.3 NaN NaN   0.933883        NaN         NaN NaN   0.174866        NaN
25  5.3 NaN NaN        NaN  97.658330         NaN NaN        NaN   0.038670
26  5.3 NaN NaN   1.650013        NaN         NaN NaN   0.541264        NaN

附言在完整的数据框中有更多的值需要映射。

【问题讨论】:

    标签: python pandas dataframe


    【解决方案1】:

    您可以使用:

    y = df.filter(regex=r'yd+')
    d = df.filter(regex=r'dd+')
    
    # target = [0.933883, 97.658330, 1.650013]
    
    # define the target values automatically
    s = y.stack()
    target = set(s[s.duplicated()])
    # {1.650013, 97.65833}
    
    drop = set()
    for x in target:
        s = d.where(y.eq(x).to_numpy()).stack().droplevel(1)
        drop.update(s.index.difference([s.idxmin()]))
    
    # drop is {29, 30}
    
    out = df.drop(drop)
    

    输出:

          x  y1  y2        y3        y4  d1  d2        d3       d4
    23  5.3 NaN NaN  0.933883       NaN NaN NaN  0.174866      NaN
    25  5.3 NaN NaN       NaN  97.65833 NaN NaN       NaN  0.03867
    26  5.3 NaN NaN  1.650013       NaN NaN NaN  0.541264      NaN
    

    【讨论】:

    • 对不起,我现在意识到我没有正确提出我的问题。这只是大约 40 行的 df 的一部分,因此要映射的值比那 3 个要多得多。
    • 您可以在target 中添加任意数量的值。或者你想自动定义那些?
    • 是的,该程序应该自动执行所有操作,而无需在代码中插入数值。
    • 也许有一种方法可以在 df 中获取具有所有唯一值的变量,然后使用 target = [variable] ?
    • @PeterM 查看我的更新
    【解决方案2】:

    可能有更有效的解决方案,但这行得通。首先,我们取列中的公共值y3y4作为列表。然后求y3和y4取共同值时d3和d4的值是多少? (v1,v2) .最后根据指定条件按索引号删除行。

    vals=sorted(list(df[['y3','y4']].stack()))
    dupes = list(set(vals[::2]) & set(vals[1::2])) #https://stackoverflow.com/a/64956890/15415267
    #dupes= [1.650013, 97.65833]
    
    for i in dupes:
        v1=df[df['y3']==i]['d3'].iloc[0]
        v2=df[df['y4']==i]['d4'].iloc[0]
        if v1 > v2:
            df=df.drop(df[df['y3']==i]['d3'].index)
        else:
            df=df.drop(df[df['y4']==i]['d4'].index)
    print(df)
    '''
          x  y1  y2        y3        y4  d1  d2        d3       d4
    23  5.3 NaN NaN  0.933883       NaN NaN NaN  0.174866      NaN
    25  5.3 NaN NaN       NaN  97.65833 NaN NaN       NaN  0.03867
    26  5.3 NaN NaN  1.650013       NaN NaN NaN  0.541264      NaN
    '''
    

    【讨论】:

    • 谢谢!我确实有一个问题。在我提取的 df 部分,y3y4 之间只有公共值,但在完整的 df 中,所有 4 列(y1y4)之间可以有公共值。我不知道如何调整您对 4 列的回答。
    猜你喜欢
    • 2014-11-04
    • 1970-01-01
    • 1970-01-01
    • 2020-06-14
    • 2022-11-20
    • 1970-01-01
    • 2019-03-22
    • 2020-11-29
    • 1970-01-01
    相关资源
    最近更新 更多