对数据框中的列进行排名的更有效方法

More efficient way to rank columns in a dataframe

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

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 是值的数据帧,每列 header 是一个整数,每列连续增加 1。排名首先由“Lineup”以单个列作为标识符创建,然后数据框“df”被连接并同时排名。

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

谢谢

您可以使用 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.

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

请注意,为了提高性能,此解决方案中的排名类型为 int32(因为此处不需要 float64)。