Python中按指定窗口大小对DataFrame指定列进行分组洗牌的实现方法
Python中按指定窗口大小对DataFrame指定列进行分组洗牌的实现方法
嘿,我来帮你搞定这个按指定窗口大小洗牌DataFrame指定列的问题!你要的Pythonic实现其实很简单,核心思路就是把数据按窗口分组,然后对每组的目标列单独打乱,其他列保持原样就行。下面给你两种靠谱的实现方式:
方法一:用groupby + sample实现(简洁优雅)
这种方法利用pandas的分组功能,一行代码就能完成组内洗牌,非常适合日常使用:
import pandas as pd import numpy as np def permute(df: pd.DataFrame, window_size: int = 10, modifiable_columns=None) -> pd.DataFrame: df_permuted = df.copy() # 如果没指定要修改的列,默认用所有列(建议明确指定,避免误改) if modifiable_columns is None: modifiable_columns = df.columns # 生成分组键:每window_size行划分为一组 group_keys = df_permuted.index // window_size # 对每组的指定列进行随机洗牌,重置索引保证和原组对齐 df_permuted[modifiable_columns] = df_permuted.groupby(group_keys)[modifiable_columns].apply( lambda group: group.sample(frac=1).reset_index(drop=True) ) return df_permuted
代码解释:
- 先复制原DataFrame,避免修改原始数据(这是好习惯哦)
group_keys = df.index // window_size会把索引0-9归为组0,10-19归为组1,以此类推,自动处理最后一组不足window_size的情况sample(frac=1)是对组内所有行进行无放回的随机打乱,reset_index(drop=True)是为了让打乱后的行索引和原组的位置对应,不会出现索引错位的问题
方法二:循环遍历窗口(适合大数据集,效率更高)
如果你的DataFrame数据量很大,循环遍历窗口的方式可能会更高效,因为避免了groupby的一些额外开销:
import pandas as pd import numpy as np def permute(df: pd.DataFrame, window_size: int = 10, modifiable_columns=None) -> pd.DataFrame: df_permuted = df.copy() if modifiable_columns is None: modifiable_columns = df.columns total_rows = len(df_permuted) # 按窗口大小遍历每一组 for start_idx in range(0, total_rows, window_size): # 计算当前窗口的结束索引,防止最后一组超出数据范围 end_idx = min(start_idx + window_size, total_rows) # 取出当前窗口的目标列数据 window_data = df_permuted.loc[start_idx:end_idx-1, modifiable_columns] # 打乱窗口内的行顺序 shuffled_window = window_data.sample(frac=1).reset_index(drop=True) # 将打乱后的数据放回原位置 df_permuted.loc[start_idx:end_idx-1, modifiable_columns] = shuffled_window.values return df_permuted
代码解释:
- 循环的起始索引每次跳window_size步,确保每个窗口不重叠
end_idx = min(start_idx + window_size, total_rows)处理最后一组行数不足的情况,不会报错- 用
.values赋值是为了跳过pandas的索引匹配,直接按位置替换,更快更稳妥
测试示例
你可以用下面的代码测试效果,直观看到洗牌前后的差异:
if __name__ == "__main__": # 创建测试用的DataFrame test_data = { '序号': list(range(25)), '字母列': [chr(ord('a') + i) for i in range(25)], '数值列': np.random.randn(25) } df = pd.DataFrame(test_data) # 指定要洗牌的列 target_cols = ['字母列', '数值列'] # 调用洗牌函数,窗口大小设为10 shuffled_df = permute(df, window_size=10, modifiable_columns=target_cols) print("原数据前15行:") print(df.head(15)) print("\n洗牌后的数据前15行:") print(shuffled_df.head(15))
注意事项
- 两种方法都不会修改原始DataFrame,因为一开始就做了深拷贝
- 如果不需要洗牌所有列,一定要明确指定
modifiable_columns,避免误改不需要变动的列(比如序号列) sample(frac=1)是完全随机打乱,如果你需要其他洗牌逻辑(比如部分打乱),可以修改这个部分的代码
备注:内容来源于stack exchange,提问作者Invader
相关产品推荐
相关产品推荐

