Jupyter内核崩溃排查:执行groupby及无groupby时均崩溃
问题分析与解决方案
核心原因
你遇到的内核崩溃完全是内存过载导致的:
- 200列的排列组合共有
200*199=39800列,搭配6000行的数据量,仅存储这些差值列(按float64计算)就需要约1.8GB内存,再加上pandas DataFrame的额外开销、列名修改和分组操作的临时数据,内存占用会直接超出Jupyter内核的默认限制,触发崩溃。
优化方案
直接跳过“生成所有列再分组”的冗余步骤,提前按分组逻辑聚合计算结果,从根源减少内存占用。
方案1:Pandas原生优化(易读性高)
按第一行差值的绝对值提前分组,直接计算每组的累加差值,避免生成上万列的中间DataFrame:
import itertools import pandas as pd def optimized_process(df): first_row = df.iloc[0] # 按第一行差值的绝对值,对所有列组合分组 comb_groups = {} for col_a, col_b in itertools.permutations(df.columns, 2): diff_first_val = first_row[col_a] - first_row[col_b] group_key = abs(diff_first_val) if group_key not in comb_groups: comb_groups[group_key] = [] comb_groups[group_key].append((col_a, col_b)) # 对每个分组计算差值的累加和 result = pd.DataFrame() for key, pairs in comb_groups.items(): # 初始化累加序列 col_sum = pd.Series([0.0]*len(df), index=df.index) for a, b in pairs: col_sum += df[a] - df[b] result[key] = col_sum return result
方案2:Numpy加速(性能最优)
利用numpy的数组操作进一步降低内存开销、提升计算速度:
import itertools import pandas as pd import numpy as np def optimized_process_np(df): arr = df.to_numpy() col_count = arr.shape[1] first_row = arr[0] # 生成所有列索引的排列组合 idx_pairs = list(itertools.permutations(range(col_count), 2)) # 计算每个组合对应的分组键(第一行差值的绝对值) a_indices = np.array([p[0] for p in idx_pairs]) b_indices = np.array([p[1] for p in idx_pairs]) group_keys = np.abs(first_row[a_indices] - first_row[b_indices]) # 按分组键聚合,计算差值的和 unique_keys, group_indices = np.unique(group_keys, return_inverse=True) result_arr = np.zeros((arr.shape[0], len(unique_keys)), dtype=arr.dtype) for i in range(len(unique_keys)): # 获取当前分组的所有组合索引 mask = group_indices == i # 计算该分组所有差值的和:sum(col_a - col_b) = sum(col_a) - sum(col_b) sum_a = arr[:, a_indices[mask]].sum(axis=1) sum_b = arr[:, b_indices[mask]].sum(axis=1) result_arr[:, i] = sum_a - sum_b # 转回DataFrame return pd.DataFrame(result_arr, index=df.index, columns=unique_keys)
额外建议
- 检查排列组合的必要性:
(a,b)和(b,a)的第一行绝对值相同,求和后结果为(a-b)+(b-a)=0,如果业务不需要这类无效零值列,可以改用itertools.combinations生成无序组合,直接减少一半计算量。 - 降低数据类型精度:如果业务允许,将数据从
float64转为float32,可直接减少一半内存占用:df = df.astype('float32')。
内容的提问来源于stack exchange,提问作者Gigi
相关产品推荐
相关产品推荐

