请教numpy.unique去除重复列的实现过程及axis参数运作机制
Numpy
np.unique(axis=1) 多维数组处理分步解析 针对你对np.unique中axis参数文档描述的困惑,以下结合你的示例数组,严格按照文档步骤拆解执行过程:
原数组定义
import numpy as np myarray = np.array( [ [ 1, 3, 7, 8, 3], [-5, 0, 9, 2, 0], [10, 11, 12, 85, 11] ] )
原数组形状为(3, 5),轴0对应行(3个元素),轴1对应列(5个元素)。
步骤1:将指定轴移至第一维度(保持其他轴顺序)
指定axis=1时,需要把**列轴(轴1)**移动到数组的第一维度位置,其他轴(轴0,行)保持顺序。可以用np.moveaxis实现:
moved_axis = np.moveaxis(myarray, 1, 0) # 输出结果: # array([[ 1, -5, 10], # [ 3, 0, 11], # [ 7, 9, 12], # [ 8, 2, 85], # [ 3, 0, 11]])
此时数组形状变为(5, 3),原数组的每一列,现在成为新数组的每一行(即第一维度的每个元素是原数组的一列)。
步骤2:展平子数组并视为结构化类型
文档中提到的"按C顺序展平子数组",这里每个子数组(即新数组的每一行)本身就是一维的,所以展平后就是子数组的元素序列。Numpy会将这些序列视为结构化类型——简单说就是把每个子数组当作一个"不可拆分的整体元素",这样后续就能以整体为单位进行比较和排序。
可以用结构化数组模拟这个过程:
structured = np.array([tuple(row) for row in moved_axis], dtype='i,i,i') # 输出结果: # array([(1, -5, 10), (3, 0, 11), (7, 9, 12), (8, 2, 85), (3, 0, 11)], # dtype=[('f0', '<i4'), ('f1', '<i4'), ('f2', '<i4')])
此时数组变成了包含5个结构化元素的一维数组,每个元素对应原数组的一列。
步骤3:按字典序排序结构化一维数组
对结构化数组进行字典序排序:先比较每个结构化元素的第一个值,第一个值小的排在前面;若第一个值相同,则比较第二个值,以此类推。执行排序后:
sorted_structured = np.sort(structured) # 输出结果: # array([(1, -5, 10), (3, 0, 11), (3, 0, 11), (7, 9, 12), (8, 2, 85)], # dtype=[('f0', '<i4'), ('f1', '<i4'), ('f2', '<i4')])
步骤4:去重并还原数组结构
对排序后的结构化数组去重,得到唯一的结构化元素:
unique_structured = np.unique(sorted_structured) # 输出结果: # array([(1, -5, 10), (3, 0, 11), (7, 9, 12), (8, 2, 85)], # dtype=[('f0', '<i4'), ('f1', '<i4'), ('f2', '<i4')])
最后将这些结构化元素还原为原数组的形状:把每个结构化元素转成列表,再将第一维度移回原轴1的位置(即转置数组):
unique_array = np.array([list(item) for item in unique_structured]).T # 输出结果: # array([[ 1, 3, 7, 8], # [-5, 0, 9, 2], # [10, 11, 12, 85]])
这与直接执行np.unique(myarray, axis=1)的结果完全一致。
核心逻辑总结
整个过程本质是将需要去重的轴(列)转换为可独立比较的"整体单元",通过结构化类型实现子数组的整体比较,排序去重后再还原回原数组的轴结构。
内容的提问来源于stack exchange,提问作者user17911
相关产品推荐
相关产品推荐

