[英]More efficient way to loop through PySpark DataFrame and create new columns
[英]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 是值的数据框,每列标题是一个整数,每连续列增加 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
。
您可以通过使用“Lineup”列直接构建fastRanks
的输出来进一步提高整体计算的速度。 必须从 Numba 函数生成的 Numpy 数组中手动设置数据框列的名称。 请注意,此优化要求所有列的类型相同,您的示例就是这种情况。
请注意,出于性能考虑,此解决方案中的等级为int32
类型(因为此处不需要float64
)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.