对数据框中的列进行排名的更有效方法
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
)。
目前我有一个数据框,我对每一列的值进行排序并将它们输出到一个新的数据框中。示例代码如下:
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
)。