【问题标题】:top k columns with values in pandas dataframe for every rowPandas 数据框中每行的值的前 k 列
【发布时间】:2017-03-01 14:07:06
【问题描述】:

我有一个如下所示的 pandas 数据框:

   A  B  C  D
0  7  2  5  2
1  3  3  1  1
2  0  2  6  1
3  3  6  2  9

可以有 100 列,在上面的例子中我只显示了 4 个。

我想为每一行提取前 k 列及其值。

我可以使用以下方法获得前 k 列:

pd.DataFrame({n: df.T[column].nlargest(k).index.tolist() for n, column in enumerate(df.T)}).T

其中,对于 k=3 给出:

   0  1  2
0  A  C  B
1  A  B  C
2  C  B  D
3  D  B  A

但我想要的是:

   0  1  2  3  4  5
0  A  7  C  5  B  2
1  A  3  B  3  C  1
2  C  6  B  2  D  1
3  D  9  B  6  A  3

有没有一种泛(a)oic 方法来实现这一点?

【问题讨论】:

    标签: python pandas dataframe


    【解决方案1】:

    你可以使用numpy解决方案:

    k = 3
    vals = df.values
    arr1 = np.argsort(-vals, axis=1)
    
    a = df.columns[arr1[:,:k]]
    b = vals[np.arange(len(df.index))[:,None], arr1][:,:k]
    
    c = np.empty((vals.shape[0], 2 * k), dtype=a.dtype)
    c[:,0::2] = a
    c[:,1::2] = b
    print (c)
    [['A' 7 'C' 5 'B' 2]
     ['A' 3 'B' 3 'C' 1]
     ['C' 6 'B' 2 'D' 1]
     ['D' 9 'B' 6 'A' 3]]
    
    df = pd.DataFrame(c)
    print (df)
       0  1  2  3  4  5
    0  A  7  C  5  B  2
    1  A  3  B  3  C  1
    2  C  6  B  2  D  1
    3  D  9  B  6  A  3
    

    【讨论】:

    • 这是非性能的,并且 nlargest 的点是分区排序; argsort 对所有内容进行排序
    【解决方案2】:
    >>> def foo(x):
    ...     r = []
    ...     for p in zip(list(x.index), list(x)):
    ...             r.extend(p)
    ...     return r
    ... 
    >>> pd.DataFrame({n: foo(df.T[row].nlargest(k)) for n, row in enumerate(df.T)}).T
       0  1  2  3  4  5
    0  A  7  C  5  B  2
    1  A  3  B  3  C  1
    2  C  6  B  2  D  1
    3  D  9  B  6  A  3
    

    或者,使用列表推导:

    >>> def foo(x):
    ...     return [j for i in zip(list(x.index), list(x)) for j in i]
    ... 
    >>> pd.DataFrame({n: foo(df.T[row].nlargest(k)) for n, row in enumerate(df.T)}).T
       0  1  2  3  4  5
    0  A  7  C  5  B  2
    1  A  3  B  3  C  1
    2  C  6  B  2  D  1
    3  D  9  B  6  A  3
    

    【讨论】:

    • 很好的解决方案,但如果数据帧中的行数约为 10k+,则列表和 for 循环会变得非常慢
    • @AbhishekThakur 我使用列表理解添加了相同解决方案的变体,但我不知道它的性能。
    • 啊,看来这不是问题。当函数被逐一应用于熊猫数据框的每一行时,问题就出现了:)
    【解决方案3】:

    这可以有效地完成这项工作:它使用在 O(n) 中找到最大 n 的 argpartition,然后只对它们进行排序。

    values=df.values
    n,m=df.shape
    k=4
    I,J=mgrid[:n,:m]
    I=I[:,:1]
    if k<m: J=(-values).argpartition(k)[:,:k]
    values=values[I,J]
    names=np.take(df.columns,J)
    J2=(-values).argsort()
    names=names[I,J2]
    values=values[I,J2]
    names_and_values=np.empty((n,2*k),object)
    names_and_values[:,0::2]=names
    names_and_values[:,1::2]=values
    result=pd.DataFrame(names_and_values)
    

    对于

       0  1  2  3  4  5
    0  A  7  C  5  B  2
    1  B  3  A  3  C  1
    2  C  6  B  2  D  1
    3  D  9  B  6  A  3
    

    【讨论】:

    • 这会引发以下错误:----> 4 d3=d[I,big3] IndexError: shape mismatch: indexing arrays could not be broadcast together with shape (4,1) (10, 3)
    • 我不明白为什么;我调整了一些东西以获得更好的通用性。你用什么 numpy 版本?
    • numpy 版本为:1.12.0
    • 我认为最后一个版本有效:问题是您的 df 比示例(4)长(10)。
    • nlargest 相比,我认为这并没有达到预期的效果。这里碰巧就是这种情况。
    猜你喜欢
    • 2016-06-13
    • 2017-09-02
    • 2019-03-26
    • 1970-01-01
    • 2015-11-18
    • 1970-01-01
    • 2018-07-26
    • 2022-11-27
    • 2022-11-29
    相关资源
    最近更新 更多