排序是对数据处理过程中常用的技术,许多编程语言中都封装了排序方法,一些工具包中也提供了相应的排序函数,最近在利用python进行数据处理时多次需要用到排序算法,在此记录一下使用的排序方法。
一. Python中内置的排序方法
Python列表有一个list.sort()方法可以直接修改原列表对象进行排序,Python还内置了一个sorted()函数对可迭代对象排序并返回新的列表对象。直接使用函数进行简单的排序
>>>sorted([5, 2, 3, 1, 4])
[1, 2, 3, 4, 5]
>>> a = [5, 2, 3, 1, 4]
>>> a.sort()
>>> a
[1, 2, 3, 4, 5]关键函数排序
list.sort() 和 sorted()函数都有一个key参数,key形参的值应该是一个函数,它接受一个参数并返回一个用于排序的键。
函数中参数 reverse 控制着升序或降序
>>> sorted("This is a test string from Andrew".split(), key=str.lower)
['a', 'Andrew', 'from', 'is', 'string', 'test', 'This']
常使用对象的一些索引作为键对复杂对象进行排序
>>> student_tuples = [('john', 'A', 15),('jane', 'B', 12),('dave', 'B', 10)]
>>> sorted(student_tuples, key=lambda student: student[2])
[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]
同样的方法也可以用于命名属性的对象
class Student:
def __init__(self, name, grade, age):
self.name = name
self.grade = grade
self.age = age
def __repr__(self):
return repr((self.name, self.grade, self.age))
student_objects = [
Student('john', 'A', 15),
Student('jane', 'B', 12),
Student('dave', 'B', 10),
]
>>> sorted(student_objects, key=lambda student: student.age) # sort by age
[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]Operator函数块
可以利用Operator的访问器功能更容易、快捷,将operator模块的itemgetter()、attrgetter()、methodcaller()函数作为sorted()的键函数。
from operator import itemgetter, attrgetter
>>>sorted(student_tuples, key=itemgetter(2))
[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]
>>> sorted(student_objects, key=attrgetter('age'))
[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]
#可以对多个关键字进行排序
>>> sorted(student_tuples, key=itemgetter(1,2))
[('john', 'A', 15), ('dave', 'B', 10), ('jane', 'B', 12)]
>>> sorted(student_objects, key=attrgetter('grade', 'age'))
[('john', 'A', 15), ('dave', 'B', 10), ('jane', 'B', 12)]
二. Numpy中的数组排序直接排序
和python内建的列表类型相似,Numpy数组可以使用sort方法按位置排序,np.sort方法返回的是已经排好序的数组拷贝,而不是对原数组的原位置排序
>>>arr = np.random.randn(6)
array([ 0.09897694, -0.77401251, 1.28342666, 0.34996876, -0.0667225 ,
0.61783311])
>>>arr.sort()
array([-0.77401251, -0.0667225 , 0.09897694, 0.34996876, 0.61783311,
1.28342666])
#对二维数组排序,按轴排序
>>>arr = np.random.randn(5,3)
array([[ 0.72718753, 1.12598459, -1.11021415],
[ 0.93991109, 1.79572359, -0.4088816 ],
[ 0.3907194 , 0.42172239, -1.30714573],
[-0.41770501, -0.21608936, -0.0639786 ],
[-0.41747941, 1.22456015, 0.44194859]])
>>>arr.sort(1)
array([[-1.11021415, 0.72718753, 1.12598459],
[-0.4088816 , 0.93991109, 1.79572359],
[-1.30714573, 0.3907194 , 0.42172239],
[-0.41770501, -0.21608936, -0.0639786 ],
[-0.41747941, 0.44194859, 1.22456015]])间接排序
在数据排序中,可能需要通过一个或多个键对数据进行排序,比如给定学生的数据,需要先按班级排序,再成绩排序,这是间接排序。
Numpy中提供了两个方法:argsort() 和 numpy.lexsort(), 可以先获得整数索引数组(索引器),索引数组的元素是原数组中相应元素的索引,然后将原数组重新排列成索引数组指定的顺序。
argsort()函数是将原始数组中的元素从小到大排列,提取其对应的index(索引
#一维数组
>>>arr = np.array([5,0,1,3,2])
>>>index = arr.argsort()
>>>index
array([1, 2, 4, 3, 0], dtype=int64)
>>>arr[index]
array([0, 1, 2, 3, 5])
#二维数组
>>>arr = np.random.randn(5,3)
array([[-0.66037395, 0.13876659, -0.24585563],
[-0.23557516, 0.81583124, -0.65606798],
[-0.4681103 , -1.23398987, 1.65237837],
[-0.2821381 , -0.62230257, -0.94928088],
[-0.45466063, -0.09264868, 2.41518593]])
>>>index0 = arr.argsort(axis = 0) #在列向上排序
array([[0, 2, 3],
[2, 3, 1],
[4, 4, 0],
[3, 0, 2],
[1, 1, 4]], dtype=int64)
>>>index1 = arr.argsort(axis = 1) #在行向上排序
array([[0, 2, 1],
[2, 0, 1],
[1, 0, 2],
[2, 1, 0],
[0, 1, 2]], dtype=int64)
#将数组中的元素按照第一列进行排序
>>>arr[index[:,0]]
array([[-0.66037395, 0.13876659, -0.24585563],
[-0.4681103 , -1.23398987, 1.65237837],
[-0.45466063, -0.09264868, 2.41518593],
[-0.2821381 , -0.62230257, -0.94928088],
[-0.23557516, 0.81583124, -0.65606798]])
argsort()默认排序是升序,可以通过如下方式进行降序:
>>>arr = np.array([5,0,1,3,2])
>>>index1 = np.argsort(arr) #按升序
>>>index2 = np.argsort(-arr) #按降序
>>>arr[index1]
array([0, 1, 2, 3, 5])
>>>arr[index2]
array([5, 3, 2, 1, 0])其他的排序算法
argsort方法利用‘kind’参数指定排序算法,‘mergesort’是唯一可用的稳定排序,但平均性能比默认的‘quicksort’方法差。
>>>arr = np.array([5,0,1,3,2])
>>>index = np.argsort(-arr, kind = 'quicksort')
>>>arr[index]
array([5, 3, 2, 1, 0])
三. Pandas中的排序
在Pandas中有两种排序方式,按索引排序:sort_index();按值排序:sort_values()。
#Series
>>>ser = pd.Series(range(5),index = ['a','e','d','s','o'])
a 0
e 1
d 2
s 3
o 4
dtype: int32
>>>ser.sort_index()
a 0
d 2
e 1
o 4
s 3
dtype: int32
#DataFrame
>>>df = pd.DataFrame(np.arange(8).reshape((2,4)),index = ['one','three'],columns = ['d','a','b','c'])
dabc
one0123
three4567
>>>df.sort_index(axis = 1, ascending = False)
dcba
one0321
three4765
>>>df.sort_values(axis = 0, ascending = False, by = ['a','c'])
dabc
three4567
one0123