【问题标题】:More efficient way to rank columns in a dataframe更有效地对数据框中的列进行排名
【发布时间】:2021-11-05 21:05:03
【问题描述】:

目前我有一个数据框,我对每一列的值进行排名并将它们输出到一个新的数据框中。示例代码如下:

df = pd.DataFrame(np.random.randint(0, 500, size=(500, 1000)), columns=list(range(0, 1000)))

ranking = pd.DataFrame(range(0, 500), columns=['Lineup'])

ranking = pd.concat([ranking, df[range(0, 1000)].rank(ascending=False, method='min')],
                        axis=1)

df 是值的数据框,每个列标题是一个整数,每连续一列增加 1。排名首先由“Lineup”以单列作为标识符创建,然后将数据框“df”连接起来并同时进行排名。

现在的问题是,这是最快的方法吗?当有数万列和数百行时,这可能比我希望的要长得多。有没有一种方法可以使用列表理解来加快速度,或者使用某种其他方法来输出列表、字典、数据框或其他任何我可以用于未来步骤的方法。

谢谢

【问题讨论】:

  • 我尝试了 scipy.stats.rankdata(~df, method='min', axis=0)np.argsort(np.argsort(~df, axis=0), axis=0) 使用不同大小的数组。每次,df.rank(ascending=False, method='min') 都比其他方法快。

标签: python pandas dataframe performance rank


【解决方案1】:

您可以使用 Numba JIT 更高效地并行计算。这个想法是并行计算每列的排名。这是生成的代码:

# Equivalent of df.rank(ascending=False, method='min')
@nb.njit('int32[:,:](int32[:,:])', parallel=True)
def fastRanks(df):
    n, m = df.shape
    res = np.empty((n, m), dtype=np.int32)

    for col in nb.prange(m):
        dfCol = -df[:, col]
        order = np.argsort(dfCol)

        # Compute the ranks with the min method
        if n > 0:
            prevVal = dfCol[order[0]]
            prevRank = 1
            res[order[0], col] = 1

            for row in range(1, n):
                curVal = dfCol[order[row]]
                if curVal == prevVal:
                    res[order[row], col] = prevRank
                else:
                    res[order[row], col] = row + 1
                    prevVal = curVal
                    prevRank = row + 1

    return res

df = pd.DataFrame(np.random.randint(0, 500, size=(500, 1000)), columns=list(range(0, 1000)))
ranking = pd.DataFrame(range(0, 500), columns=['Lineup'])
ranking = pd.concat([ranking, pd.DataFrame(fastRanks(df[range(0, 1000)].to_numpy()))], axis=1)

在我的 6 核机器上,秩的计算大约快 7 倍。整体计算受限于慢速pd.concat

您可以通过使用“Lineup”列直接构建fastRanks 的输出来进一步提高整体计算的速度。数据框列的名称必须从 Numba 函数生成的 Numpy 数组中手动​​设置。请注意,此优化要求所有列的类型相同,您的示例就是这种情况。

请注意,出于性能考虑,此解决方案中的等级为 int32 类型(因为此处不需要 float64)。

【讨论】:

  • 完美,谢谢!从每循环 2.3 秒到每循环 0.33 秒!
猜你喜欢
  • 2011-11-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-21
  • 1970-01-01
  • 2017-08-15
相关资源
最近更新 更多