快速排序-提取排序索引 算法

引言

上篇文章的运行结果会返回一个特征重要性列表,表示了一个预测分类问题中,各变量对分类的贡献程度,为了方便,我们需要将重要性排序,从而直观看的哪些是重要的特征,哪些是不重要的,其次,为了提高效率,有时我们需要的是特征对应的索引,而不是特征具体的值,例如我们需要首先知道是几号特征最重要,其次才需要知道它的重要性占比是多少,所以这篇文章主要介绍排序算法和返回索引.

回顾

[ 0.01711044  0.00919911  0.07351338  0.15271884  0.05239271  0.03671487
  0.0210451   0.14226094  0.01203942  0.07059542  0.02364601  0.03109124
  0.05005074  0.03305065  0.02808322  0.02442624  0.02248264  0.06917138
  0.07207685  0.02974831  0.02858248]

这是上节返回的特征重要性表,共有21个特征,特征重要性已进行归一化,排序并返回索引得到的结果是:

重要特征排序(按索引从大到小): [3, 7, 2, 18, 9, 17, 4, 12, 5, 13, 11, 19, 20, 14, 15, 10, 16, 6, 0, 8, 1]

最大的元素索引是[3],对应0.1527,其次是[7],对应的是0.1422,依次类推.

快速排序思想

快速排序的中心思想是递归,时间复杂度在O(N*logN)到O(N*N)之间,通过初始化一个列表值,以这个值为基准,也就是pivot,然后将列表分为两个部分,小于等于pivot的一部分Less,和大于pivot的一部分More,然后针对这两个部分,把这两个部分看做两个单独的list,重复之前的确定pivot,划分Less,More的过程,直到最终列表划分完毕,即列表长度小于等于1时,因为此时只有一个元素,已经不需要排序.下面简单实现一个快速排序.

1)初始数列[7,3,4,6,9,5,1,2,8],按列表第一个位置即0索引为分界线,分为两部分.

2)分为比7小的一组和比7大的一组,分别对这两组的索引0,即数字3和1数字9为界限,递归划分.

3)左边部分是比3小的和比3大的,右边部分是比9小的和比9大的(没有比9大的了).

4)再次递归,这次数组长度都很短了,再次递归,得到最后结果.

实现

这里我们使用三种方法实现快排返回索引,第一种是numpy自带的argsort()函数实现,剩下两种分别是基于列表和基于指针的快速排序,后面再介绍两种快速排序算法的不同.

1)argsort()方法:

argsort方法是numpy库自带的排序并返回索引的方法,下面实现一下:

import numpy as np #导入numpy库
#转换为array
example = np.array([0.01711044,0.00919911,0.07351338,0.15271884,0.05239271,0.03671487,
                    0.0210451 ,0.14226094,0.01203942,0.07059542,0.02364601,0.03109124,
  		    0.05005074,0.03305065,0.02808322,0.02442624,0.02248264,0.06917138,
                    0.07207685,0.02974831,0.02858248])
importance_list = np.argsort(-example)#argsort()方法
print(importance_list)

返回结果

[ 3  7  2 18  9 17  4 12  5 13 11 19 20 14 15 10 16  6  0  8  1]

argsort()方法默认返回从小到大排序的索引,因为我们的问题是预测变量重要性从高到低,所以添加一个'-'号,负责翻转列表,类似列表的reverse()方法.

2)快速排序基于列表:

def quicksort_list(array):
	if len(array) < 2:#基线条件,保证在一定程度退出递归,避免死循环
		return array
	else:
		pivot = array[0]
		less = [i for i in array[1:] if i <= pivot]#比pivot小的
		rather = [i for i in array[1:] if i > pivot]#比pivot大的
	return quicksort_list(less) + [pivot] + quicksort_list(rather)

3)快速排序基于指针:

def quicksort(list,low,high):#递归主程序
	if high > low:
		k = divide_list(list,low,high)
		quicksort(list,low,k-1)
		quicksort(list,k+1,high)

def divide_list(list,low,high):#根据指针,分为一边大一边小
	left = low#初始化左指针
	right = high#初始化右指针
	k = list[low]#初始值
	while left < right:#不断比较改变指针位置
		while list[left] <= k:
			left = left + 1
		while list[right] > k:
			right = right - 1
		if left < right:#指针停止前进后退时互换元素直到两边相遇
			list[left],list[right] = list[right],list[left]
	list[low] = list[right]#交换元素
	list[right] = k#返回分界点
	return right

4)返回索引

def sort_index(list):
	index = {}
	for i in range(len(list)):
		index[list[i]] = i
	return index

sort_index()函数负责构建一个元素{值:索引}的字典,保存元素索引号

def sorted(list_sort):
	index_of_list = sort_index(list_sort)
	sorted = quick_sort(list_sort)
	# print(sorted)
	rank = []
	for i in sorted:
		rank.append(index_of_list[i])
	print('重要特征排序(按索引从大到小):',list(reversed(rank)))
	return rank[::-1]

sorted()函数通过快排获得元素,并通过列表和字典将排序好的元素索引返回.通过这两个函数和上面任一个快速排序程序,即可实现argsort()的功能.

5)快排+返回索引

这里使用第一种快排加返回索引函数,实现返回索引的功能.另一种快排同理.

def quicksort(array):
	if len(array) < 2:
		return array
	else:
		pivot = array[0]
		less = [i for i in array[1:] if i <= pivot]
		rather = [i for i in array[1:] if i > pivot]
	return quicksort(less) + [pivot] + quicksort(rather)

def sort_index(list):
	index = {}
	for i in range(len(list)):
		index[list[i]] = i
	return index

def sorted(list_sort):
	index_of_list = sort_index(list_sort)
	sorted = quicksort(list_sort)
	# print(sorted)
	rank = []
	for i in sorted:
		rank.append(index_of_list[i])
	print('大小排序(按索引从大到小):',list(reversed(rank)))
	return rank[::-1]

importance = [0.01711044,0.00919911,0.07351338,0.15271884,0.05239271,0.03671487,
           0.0210451 ,0.14226094,0.01203942,0.07059542,0.02364601,0.03109124,
  		   0.05005074,0.03305065,0.02808322,0.02442624,0.02248264,0.06917138,
           0.07207685,0.02974831,0.02858248]
sorted(importance)
大小排序(按索引从大到小): [3, 7, 2, 18, 9, 17, 4, 12, 5, 13, 11, 19, 20, 14, 15, 10, 16, 6, 0, 8, 1]

ok,大功告成,对照前面argsort()的结果与原始数组,程序运行没问题了~

总结

快速排序+返回索引大概就这么多,至于为什么要有基于列表索引和基于指针索引两种,是因为基于列表排序的话,虽然代码简单,但每次迭代都会产生两个新的列表,数据量小还好,数据量大的话,会占用很多的内存去存储,因此从系统开销时间开销上考虑,针对单个列表使用指针效率会更高一些.其次,针对一些升序或降序的数组,以第一个元素为pivot值往往效果不佳,这时可以考虑样本中值,或者首尾平均数等作为pivot值,效果会有所提升。每次写博客都能顺便p图玩,还是很有趣的,以后会有更多的图解算法和机器学习O.O

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BIT_666

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值