np.lexsort如何为每个排序列单独指定升降序(支持字符串列场景)
Numpy多列排序自定义每列升降序的实现方法
numpy的np.lexsort本身仅支持所有排序键按升序排列,要实现自定义每列升降序,核心逻辑是:对需要降序排列的列,将其转换为升序排列等价于原列降序排列的键,再传入lexsort即可。
示例场景直接解法
你的示例数组所有元素为字符串类型,排序键为数值内容,直接转整数取负即可作为降序的键:
import numpy as np arr = np.array([list("aaabbb"),[1,2,3,1,4,3],[1,2,3,4,6,6]]).T # 按列2(索引2)优先降序,再按列1(索引1)降序 idx = np.lexsort([ -arr[:,1].astype(int), # 第二排序规则:列1降序 -arr[:,2].astype(int) # 第一排序规则:列2降序 ]) sorted_arr = arr[idx]
运行后得到的结果和你给出的预期完全一致。
通用实现方案
如果要支持任意数据类型(含字符串、数值等所有支持比较的类型)、自由指定排序列和每个列的升降序,可以封装为通用函数:
def numpy_multi_sort(arr, sort_cols, ascending): """ 通用numpy多列自定义排序函数 :param arr: 输入numpy数组 :param sort_cols: 排序列索引列表,优先级从低到高(和lexsort参数顺序一致) :param ascending: 布尔列表,和sort_cols长度一一对应,True为升序,False为降序 :return: 排序后的数组 """ sort_keys = [] for col_idx, is_asc in zip(sort_cols, ascending): col_data = arr[:, col_idx] # 生成列的全局排名,兼容所有可比较类型 col_rank = np.argsort(np.argsort(col_data)) # 降序则对排名取负,lexsort升序排列负排名等价于原列降序 if not is_asc: col_rank = -col_rank sort_keys.append(col_rank) # 获取排序索引 sort_idx = np.lexsort(sort_keys) return arr[sort_idx]
如果你习惯pandas的调用风格(排序列表靠前的优先级更高),可以再加一层适配:
def numpy_multi_sort_pd(arr, by_cols, ascending): """ 对齐pandas sort_values调用风格的多列排序 :param arr: 输入numpy数组 :param by_cols: 排序列索引列表,优先级从高到低(和pandas by参数一致) :param ascending: 布尔列表,和by_cols长度一一对应,True为升序,False为降序 :return: 排序后的数组 """ # 反转顺序适配lexsort的优先级规则 return numpy_multi_sort(arr, by_cols[::-1], ascending[::-1])
调用示例
# 对应你的需求:优先按列2降序,再按列1降序 sorted_arr = numpy_multi_sort_pd(arr, by_cols=[2, 1], ascending=[False, False])
内容的提问来源于stack exchange,提问作者FredMaster
相关产品推荐
相关产品推荐

