如何基于Numpy邻域单元格计算环绕平均与基础运算
问题描述
我有一个10×10的Numpy数组,需要对每个单元格完成两个计算:
- 基于其上下左右邻域单元格计算指标(公式为
|邻域值-当前值|/(邻域值+当前值)) - 基于单元格的i、j索引做加权移动平均:8个紧邻单元格权重占比70%,16个非紧邻单元格权重占比30%
同时不确定如何处理边缘(边界及角落)单元格的窗口核不完整问题,寻求Pythonic的实现方式。
用户代码尝试
import numpy as np import pandas as pd import matplotlib.pyplot as plt noisy_data = [[0.0467251, 0.0529133, 0.0775945, 0.0640082, 0.0439774, 0.0915829, 0.0547699, 0.0826791, 0.0883616, 0.0977739], [0.0875183, 0.0790368, 0.101146 , 0.0777582, 0.104289 , 0.0775479, 0.156569 , 0.0999909, 0.0905242, 0.161871 ], [0.1427 , 0.1211 , 0.15661 , 0.113337 , 0.135986 , 0.1384 , 0.181515 , 0.159102 , 0.200004 , 0.187535 ], [0.163381 , 0.186425 , 0.174798 , 0.14191 , 0.1514 , 0.166044 , 0.199063 , 0.146319 , 0.173303 , 0.144067 ], [0.182485 , 0.16901 , 0.11 , 0.127162 , 0.0858656, 0.1564 , 0.161187 , 0.0588985, 0.110706 , 0.0560944], [0.103804 , 0.109948 , 0.0707144, 0.0493536, 0.0471329, 0.0708205, 0.048201 , 0.0487304, 0.069967 , 0.0947939], [0.0382397, 0.0918 , 0.101197 , 0.102453 , 0.135943 , 0.0867575, 0.123071 , 0.0970329, 0.099906 , 0.101536 ], [0.113361 , 0.167597 , 0.141526 , 0.0792396, 0.118 , 0.065764 , 0.0915817, 0.1183 , 0.149376 , 0.118608 ], [0.10647 , 0.1566 , 0.1303 , 0.139754 , 0.174465 , 0.148458 , 0.187625 , 0.132805 , 0.171687 , 0.158161 ], [0.15319 , 0.174204 , 0.161628 , 0.127377 , 0.173368 , 0.145292 , 0.208068 , 0.168076 , 0.14961 , 0.124334 ]] noisy_data = np.array(noisy_data).reshape(10, 10) plt.imshow(noisy_data, cmap="jet") plt.colorbar() new_df = pd.DataFrame() # 注:原代码存在语法错误(括号不匹配)和逻辑错误(循环变量遍历数组而非索引) new_df['left_neighboring_index'] = [(np.abs(noisy_data[i-1] - noisy_data[i]))/(noisy_data[i-1] + noisy_data[i]) for i in noisy_data] new_df['right_neighboring_index'] = [(np.abs(noisy_data[i+1] - noisy_data[i]))/(noisy_data[i+1] + noisy_data[i]) for i in noisy_data] new_df['bottom_neighboring_index'] = [(np.abs(noisy_data[j-1] - noisy_data[j]))/(noisy_data[j-1] + noisy_data[j]) for i in noisy_data] new_df['top_neighboring_index'] = [(np.abs(noisy_data[j+1] - noisy_data[j]))/(noisy_data[j+1] + noisy_data[j]) for i in noisy_data] new_df['weighted_moving_average_size_20_(8+12)'] = ...?
解决方案
一、邻域指标计算
原代码核心问题是循环逻辑错误,需遍历数组的行、列索引而非数组元素。边缘单元格无对应邻域,可直接赋值NaN,或通过补边处理。
实现代码
import numpy as np import pandas as pd noisy_data = np.array(noisy_data).reshape(10, 10) rows, cols = noisy_data.shape # 初始化结果数组,默认填充NaN left_idx = np.full((rows, cols), np.nan) right_idx = np.full((rows, cols), np.nan) top_idx = np.full((rows, cols), np.nan) bottom_idx = np.full((rows, cols), np.nan) # 计算内部单元格的邻域指标(排除边缘行/列) for i in range(1, rows-1): for j in range(1, cols-1): current = noisy_data[i, j] # 左邻域 left_val = noisy_data[i, j-1] left_idx[i, j] = np.abs(left_val - current) / (left_val + current) # 右邻域 right_val = noisy_data[i, j+1] right_idx[i, j] = np.abs(right_val - current) / (right_val + current) # 上邻域 top_val = noisy_data[i-1, j] top_idx[i, j] = np.abs(top_val - current) / (top_val + current) # 下邻域 bottom_val = noisy_data[i+1, j] bottom_idx[i, j] = np.abs(bottom_val - current) / (bottom_val + current) # 转为DataFrame new_df = pd.DataFrame({ 'left_neighboring_index': left_idx.flatten(), 'right_neighboring_index': right_idx.flatten(), 'top_neighboring_index': top_idx.flatten(), 'bottom_neighboring_index': bottom_idx.flatten() })
二、加权移动平均计算
定义5×5窗口:中心为当前单元格,8个3×3范围内的紧邻单元格权重占70%(每个权重0.7/8),16个5×5外围单元格权重占30%(每个权重0.3/16)。用np.pad的edge模式补边,解决边缘窗口不完整问题。
基础循环实现
# 定义5×5权重核 kernel = np.zeros((5, 5)) # 3×3区域(除中心):8个紧邻单元格 kernel[1:4, 1:4] = 0.7 / 8 kernel[2, 2] = 0 # 中心单元格不参与计算 # 外围区域:16个单元格 kernel[0, :] = 0.3 / 16 kernel[4, :] = 0.3 / 16 kernel[:, 0] = 0.3 / 16 kernel[:, 4] = 0.3 / 16 # 补边处理边缘 padded_data = np.pad(noisy_data, pad_width=2, mode='edge') # 初始化结果数组 weighted_avg = np.zeros_like(noisy_data) # 遍历计算加权平均 for i in range(rows): for j in range(cols): window = padded_data[i:i+5, j:j+5] weighted_avg[i, j] = np.sum(window * kernel) # 加入DataFrame new_df['weighted_moving_average'] = weighted_avg.flatten()
高效向量化实现(推荐)
用scipy.ndimage.convolve替代循环,大幅提升效率:
from scipy.ndimage import convolve # 复用之前定义的权重核 kernel = np.zeros((5, 5)) kernel[1:4, 1:4] = 0.7 / 8 kernel[2, 2] = 0 kernel[0, :] = 0.3 / 16 kernel[4, :] = 0.3 / 16 kernel[:, 0] = 0.3 / 16 kernel[:, 4] = 0.3 / 16 # mode='nearest'自动补边处理边缘 weighted_avg = convolve(noisy_data, kernel, mode='nearest') new_df['weighted_moving_average_vectorized'] = weighted_avg.flatten()
内容的提问来源于stack exchange,提问作者2023_resolution
相关产品推荐
相关产品推荐

