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

news/2024/5/19 23:36:53 标签: 快速排序, 算法, 返回索引

引言

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

回顾

[ 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


http://www.niftyadmin.cn/n/1236183.html

相关文章

线性模型-线性回归与实现 西瓜书

线性模型 给定d个属性描述的实例x (x1,x2,...,xd),其中xi是x在第i个属性上的取值&#xff0c;线性模型想要学得一个通过属性的线性组合来进行预测的函数&#xff0c;即&#xff1a; 一般写成向量模型&#xff1a; 线性回归 给定数据集D{(x1,y1),(x2,y2),(x3,y3)...(xm,ym)} …

810. 黑板异或游戏

2021-05-22 LeetCode每日一题 链接&#xff1a;https://leetcode-cn.com/problems/chalkboard-xor-game/ 标签&#xff1a;数学、异或 题目 黑板上写着一个非负整数数组 nums[i] 。Alice 和 Bob 轮流从黑板上擦掉一个数字&#xff0c;Alice 先手。如果擦除一个数字后&#xf…

线性模型-局部加权线性回归 机器学习实战

局部加权线性回归 线性回归的一个问题是有可能出现欠拟合&#xff0c;因为它求的是具有最小均方误差的无偏估计&#xff0c;显然模型欠拟合将无法做出很好的回归预测&#xff0c;所以有些方法允许在估计中引入一些偏差&#xff0c;从而降低预测的均方误差。局部线性加权的思想…

MySQL批量插入测试数据

有时候我们需要往表中批量插入几万甚至几十万条数据&#xff0c;这时候总不可能手工一条条插入的&#xff0c;这估计得累死人&#xff0c;可以利用MySQL的函数和存储过来实现这个需求。 1、建立测试需要的表 CREATE TABLE dept ( id INT(11) NOT NULL AUTO_INCREMENT, deptNa…

数据结构笔记-栈与队列 python

概述 栈与队列是程序设计中被广泛应用的两种重要的数据结构&#xff0c;都是在特定范围的存储单元内存储数据&#xff0c;这些数据都可以被重新取出使用&#xff0c;与线性表相比&#xff0c;他们的插入和删除受到更多的约束&#xff0c;固又称限定性的线性表结构。他们是最简…

421. 数组中两个数的最大异或值

链接&#xff1a;https://leetcode-cn.com/problems/maximum-xor-of-two-numbers-in-an-array/ 标签&#xff1a;位运算、字典树。 题目 给你一个整数数组 nums &#xff0c;返回 nums[i] XOR nums[j] 的最大运算结果&#xff0c;其中 0 ≤ i ≤ j < n 。 进阶&#xff1a…

数据结构笔记-实现链表反转 python

概述 这里主要针对单向链接表&#xff0c;单向连接表的结点是一个二元组&#xff0c;其中元素域elem保存着作为表元素的数据项&#xff0c;连接域next包含着同一个表里下一个节点的标识。在最常见的单链表里&#xff0c;与表里n个元素对应的n个结点通过连接形成一条结点链&…

数据结构笔记-二叉树及其实现 python

概述 二叉树是一种最简单的树形结构&#xff0c;其特点是树中每个结点至多关联到两个后继结点&#xff0c;也就是&#xff0c;一个节点可以关联到的结点可以为0,1,2&#xff0c;这也是二叉树一个节点度的定义&#xff0c;另一个特点是结点关联的后继结点明确的分左右&#xff…