【问题标题】:Sort each row absolute value independent of columns along with column names对独立于列的每行绝对值以及列名进行排序
【发布时间】:2020-06-11 10:08:36
【问题描述】:

我有一个类似格式的数据框:

df = pd.DataFrame({
 'p1': [0, 0, 1, 1, -2],
 'p2': [9, 2, 3, -5, 3],
 'p3': [1, 3, 10, 3, 7],
 'p4': [4, 4, 7, 1, 10]})

    p1  p2  p3  p4
0   0   9   1   4
1   0   2   3   4
2   1   3   10  7
3   1   -5  3   1
4   -2  3   7   10

预期输出:

top1    top2
p2:9    p4:4
p4:4    p3:3
p3:10   p4:7
p2:-5   p3:3
p4:10   p3:7

通过大量研究,我能够对排序后的数组进行排序并获得索引。我还能够用列替换索引。但我无法将它们与行值连接起来。

nlargest = 3
order = np.argsort(-df.abs().values, axis=1)[:, :nlargest]
result = pd.DataFrame(df.columns[order], 
                      columns=['top{}'.format(i) for i in range(1, nlargest+1)])

  top1 top2 top3
0   p2   p4   p3
1   p4   p3   p2
2   p3   p4   p2
3   p2   p3   p1
4   p4   p3   p2

使用上述方法,我尝试对不同 DataFrame 中的行进行排序,后来想到将它们连接起来。但我找不到正确的方法来做到这一点。我知道这不是最佳方式。

result2 = pd.DataFrame(np.sort(df.values, axis=0), index=df.index, columns=df.columns)
result2 = result2.iloc[:, 0:nlargest]
result2.columns = columns=['top{}'.format(i) for i in range(1, nlargest+1)]

   top1  top2  top3
0    -2    -5     1
1     0     2     3
2     0     3     3
3     1     3     7
4     1     9    10

请帮我更正排序和获得预期格式的最短方法。

【问题讨论】:

  • 最优方式意味着最好的性能?

标签: python python-3.x pandas dataframe sorting


【解决方案1】:

仅使用 numpy 解决方案以获得最佳性能:

nlargest = 3
arr = df.to_numpy()
order = np.argsort(-np.abs(arr), axis=1)[:, :nlargest]
print (order)
[[1 3 2]
 [3 2 1]
 [2 3 1]
 [1 2 0]
 [3 2 1]]

想法是将numpy数组arr中原始数据的顺序更改为order数组,如this解决方案:

a = arr[np.arange(arr.shape[0])[:, None], order]
print (a)
[[ 9  4  1]
 [ 4  3  2]
 [10  7  3]
 [-5  3  1]
 [10  7  3]]

因此您可以添加转换为字符串的值:

result = pd.DataFrame(df.columns[order] + ':' + a.astype(str), 
                      columns=['top{}'.format(i) for i in range(1, nlargest+1)])

print (result)
    top1  top2  top3
0   p2:9  p4:4  p3:1
1   p4:4  p3:3  p2:2
2  p3:10  p4:7  p2:3
3  p2:-5  p3:3  p1:1
4  p4:10  p3:7  p2:3

【讨论】:

  • 感谢@jezrael 的努力
【解决方案2】:

使用DataFrame.transformDataFrame.lookup

result = result.transform(lambda s: s + ':' + df.lookup(s.index, s).astype(str))

# print(result)
    top1  top2  top3
0   p2:9  p4:4  p3:1
1   p4:4  p3:3  p2:2
2  p3:10  p4:7  p2:3
3  p2:-5  p3:3  p1:1
4  p4:10  p3:7  p2:3

【讨论】:

    【解决方案3】:

    由于您需要创建字符串,我们可以使用.stack.groupby.cumcount 来获取前n 个值。

    largest_n = 3
    
    s = (
        df.stack()
        .sort_values(ascending=False)
        .groupby(level=0)
        .head(largest_n)
        .reset_index(1)
        .astype(str)
        .agg(":".join, axis=1)
        .to_frame("vals")
    )
    

    df1 = (
        (
            s.assign(key=s.groupby(level=0).cumcount() + 1)
            .set_index("key", append=True)
            .unstack()
        )
        .add_prefix("Top_")
        .droplevel(level=0, axis=1)
    )
    

    print(df1)
    
    key  Top_1 Top_2 Top_3
    0     p2:9  p4:4  p3:1
    1     p4:4  p3:3  p2:2
    2    p3:10  p4:7  p2:3
    3     p3:3  p1:1  p4:1
    4    p4:10  p3:7  p2:3
    

    【讨论】:

    • @supreeth2812 没问题,我会选择 Jezrael 的解决方案,因为它更适合更大的数据集,并且比使用 lambda 更快
    • 你是对的! @jazrael 解决方案实际上更快并且使用它是有意义的,因为数据集很大并且必须多次运行。
    猜你喜欢
    • 1970-01-01
    • 2013-09-14
    • 2019-02-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-20
    • 2021-08-24
    相关资源
    最近更新 更多