为什么在将pandas DataFrame拆分成块之后我的func运行得更快,而不是简单地执行apply()?

Eri*_* He 5 python pandas

我试着分别在pandas数据框中随机播放每一列.这里写的函数:

def shuffle_x(x):
    x = x.copy()
    np.random.shuffle(x)

    return x


def shuffle_table(df):
    df_shuffled = df.apply(shuffle_x, raw = True, axis = 0)
    return df_shuffled
Run Code Online (Sandbox Code Playgroud)

现在,我正在测试一个包含30000行和1000列的pandas数据帧df,如果我直接这样做shuffle_table(df),这真的很慢,需要超过1500秒.但是,如果我做这样的事情:

df_split = np.split(df, 100, axis = 1)
df_shuffled = pd.concat([shuffle_table(x) for x in df_split], axis = 1)
Run Code Online (Sandbox Code Playgroud)

这要快得多,只需60秒

我最好的客人是这个问题与pandas为生成新数据帧分配空间的方式有关.

此外,我能想出的最快方法是:

tmp_d = {}
for col in df.columns:
    tmp_val = df[col].values
    np.random.shuffle(tmp_val)
    tmp_d[col] = tmp_val

df_shuffled = pd.DataFrame(tmp_d)
df_shuffled = df_shuffled[df.columns]
Run Code Online (Sandbox Code Playgroud)

这大约需要15秒

Bre*_*arn 7

它更快,因为它没有做同样的事情.

要完全混洗确保完全随机化的序列需要至少O(n)时间.所以你的DataFrame越大,洗牌所需的时间就越长.

你的第二个例子不等同,因为它不是完全随机的.它只会洗掉个别块.如果有一个列[1, 2, 3, ..., 29999, 30000],你的第二个方法永远不会产生类似的结果[1, 30000, 2, 29999, ...],因为它永远不会将序列的开头与结尾混合在一起.基于块的改组无法实现许多可能的改组.

从理论上讲,如果将DataFrame分成100个相同大小的块,您可能会希望每个块以比整体快100倍的速度进行洗牌.基于你的时间,看起来它实际上花费了比这更长的次洗牌,我猜这至少部分是由于首先创建子表的开销.