Python中如何高效实现数据到矩阵的映射,加速指定循环代码段
待优化代码段
# the part I want to speed up for x, y_dict in zip(x_data, y_data): x_index = x_to_index[x] for y_key, y_data in y_dict.items(): y_slice = slice(*y_to_index[y_key]) total_matrix[ y_slice, x_index ] += y_data latest_value[ y_slice, x_index ] = y_data n_matrix[ y_slice, x_index ] += 1
优化方案
以下两种方案均可实现性能大幅提升,可根据你的场景选择:
方案1:Numba JIT编译优化(最推荐,提速100倍以上)
仅需极小的代码改动,通过Numba的即时编译能力将Python循环直接编译为机器码,消除Python解释器开销,是数值类循环优化的首选方案。
首先安装依赖:pip install numba
优化后代码:import numpy as np from numba import njit # 预处理映射与数据为数组格式,适配Numba编译要求 x_index_arr = np.array([x_to_index[x] for x in x_data]) max_y_key = max(y_to_index.keys()) y_index_arr = np.zeros((max_y_key + 1, 2), dtype=np.int32) for k, (start, end) in y_to_index.items(): y_index_arr[k] = [start, end] y_val_arr = np.zeros((len(y_data), max_y_key + 1), dtype=np.int32) for i, y_dict in enumerate(y_data): for k, v in y_dict.items(): y_val_arr[i, k] = v @njit def run_update(x_index_arr, y_index_arr, y_val_arr, total_matrix, latest_value, n_matrix): x_count = len(x_index_arr) y_key_count = y_val_arr.shape[1] for x_idx in range(x_count): col = x_index_arr[x_idx] for y_k in range(y_key_count): val = y_val_arr[x_idx, y_k] y_start, y_end = y_index_arr[y_k] total_matrix[y_start:y_end, col] += val latest_value[y_start:y_end, col] = val n_matrix[y_start:y_end, col] += 1 return total_matrix, latest_value, n_matrix # 执行更新,首次调用会有编译开销,后续调用无额外开销 total_matrix, latest_value, n_matrix = run_update(x_index_arr, y_index_arr, y_val_arr, total_matrix, latest_value, n_matrix)方案2:纯NumPy向量化实现(无额外依赖,提速10~50倍)
不需要安装第三方依赖,仅通过NumPy的原生向量化操作替代Python循环,适合不能引入新依赖的场景。
优化后代码:import numpy as np # 预处理所有映射 x_indices = np.array([x_to_index[x] for x in x_data]) y_ranges = np.array([y_to_index[k] for k in range(100)]) all_rows = [] all_cols = [] all_vals = [] for col, y_dict in zip(x_indices, y_data): for y_k, val in y_dict.items(): y_s, y_e = y_ranges[y_k] rows = np.arange(y_s, y_e, dtype=np.int32) all_rows.append(rows) all_cols.append(np.full_like(rows, col)) all_vals.append(np.full_like(rows, val)) all_rows = np.concatenate(all_rows) all_cols = np.concatenate(all_cols) all_vals = np.concatenate(all_vals) # 批量执行累加操作 np.add.at(total_matrix, (all_rows, all_cols), all_vals) np.add.at(n_matrix, (all_rows, all_cols), 1) # 处理latest_value,取每个位置最后一次的赋值 _, last_idx = np.unique(np.stack([all_rows, all_cols], axis=1)[::-1], axis=0, return_index=True) last_idx = len(all_rows) - 1 - last_idx latest_value[all_rows[last_idx], all_cols[last_idx]] = all_vals[last_idx]
内容的提问来源于stack exchange,提问作者financial_physician
相关产品推荐
相关产品推荐

