做者|B. Chen
编译|VK
来源|Towards Data Sciencehtml
Pandas DataFrame有一个内置方法sort_values(),能够根据给定的变量对值进行排序。该方法自己使用起来至关简单,可是它不适用于自定义排序,例如,python
t恤尺寸:XS、S、M、L和XLgit
月份:一月、二月、三月、四月等github
星期几:周1、周2、周3、周4、周5、周六和周日。api
在本文中,咱们将了解如何对Pandas DataFrame进行自定义排序。app
请查看个人Github repo以获取源代码:https://github.com/BindiChen/machine-learning/blob/master/data-analysis/017-pandas-custom-sort/pandas-custom-sort.ipynb机器学习
假设咱们有一个关于服装店的数据集:ide
df = pd.DataFrame({ 'cloth_id': [1001, 1002, 1003, 1004, 1005, 1006], 'size': ['S', 'XL', 'M', 'XS', 'L', 'S'], })
咱们能够看到,每一块布料都有一个尺寸值,数据应该按如下顺序排序:学习
XS表明特大号ui
S表明小号
M表明中号
L表明大号
XL为特大号
可是,当调用sort_values('size')时,将获得如下输出。
输出不是咱们想要的,但它在技术上是正确的。实际上,sort_values()是按数字顺序对数值数据排序,对对象数据按字母顺序排序。
如下是两种常见的解决方案:
为自定义排序建立新列
使用CategoricalDtype将数据强制转换为具备有序性的类别类型
在这个解决方案中,须要一个映射数据帧来表示一个自定义排序,而后根据映射建立一个新的列,最后咱们能够按新列对数据进行排序。让咱们经过一个例子来看看这是如何工做的。
首先,让咱们建立一个映射数据帧来表示自定义排序。
df_mapping = pd.DataFrame({ 'size': ['XS', 'S', 'M', 'L', 'XL'], }) sort_mapping = df_mapping.reset_index().set_index('size')
以后,使用sort_mapping中的映射值建立一个新的列 size_num。
df['size_num'] = df['size'].map(sort_mapping['index'])
最后,按新的列大小对值进行排序。
df.sort_values('size_num')
这固然是咱们的工做。但它建立了一个备用列,在处理大型数据集时效率可能会下降。
咱们可使用CategoricalDtype更有效地解决这个问题。
CategoricalDtype是具备类别和顺序的分类数据的类型[1]。它对于建立自定义排序很是有用[2]。让咱们经过一个例子来看看这是如何工做的。
首先,让咱们导入CategoricalDtype。
from pandas.api.types import CategoricalDtype
而后,建立一个自定义类别类型cat_size_order
第一个参数设置为['XS'、'S'、'M'、'L'、'XL']做为尺寸的惟一值。
第二个参数ordered=True,将此变量视为有序。
cat_size_order = CategoricalDtype( ['XS', 'S', 'M', 'L', 'XL'], ordered=True )
而后,调用astype(cat_size_order)将大小数据强制转换为自定义类别类型。经过运行df['size'],咱们能够看到size列已经被转换为一个类别类型,其顺序为[XS<S<M<L<XL]。
>>> df['size'] = df['size'].astype(cat_size_order) >>> df['size'] 0 S 1 XL 2 M 3 XS 4 L 5 S Name: size, dtype: category Categories (5, object): [XS < S < M < L < XL]
最后,咱们能够调用相同的方法对值进行排序。
df.sort_values('size')
这样效果更好。让咱们来看看原理是什么。
如今size列已经被转换为category类型,咱们可使用.cat访问器以查看分类属性。在幕后,它使用codes属性来表示有序变量的大小。
让咱们建立一个新的列代码,这样咱们能够并排比较大小和代码值。
df['codes'] = df['size'].cat.codes df
咱们能够看到XS、S、M、L和XL的代码分别为0、一、二、三、4和5。codes是类别实际值。经过运行df.info(),咱们能够看到其实是int8。
>>> df.info() <class 'pandas.core.frame.DataFrame'> RangeIndex: 6 entries, 0 to 5 Data columns (total 3 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 cloth_id 6 non-null int64 1 size 6 non-null category 2 codes 6 non-null int8 dtypes: category(1), int64(1), int8(1) memory usage: 388.0 bytes
接下来,让咱们把事情变得更复杂一点。这里,咱们将按多个变量对数据帧进行排序。
df = pd.DataFrame({ 'order_id': [1001, 1002, 1003, 1004, 1005, 1006, 1007], 'customer_id': [10, 12, 12, 12, 10, 10, 10], 'month': ['Feb', 'Jan', 'Jan', 'Feb', 'Feb', 'Jan', 'Feb'], 'day_of_week': ['Mon', 'Wed', 'Sun', 'Tue', 'Sat', 'Mon', 'Thu'], })
相似地,让咱们建立两个自定义类别类型cat_day_of_week和cat_month,并将它们传递给astype()。
cat_day_of_week = CategoricalDtype( ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'], ordered=True ) cat_month = CategoricalDtype( ['Jan', 'Feb', 'Mar', 'Apr'], ordered=True, ) df['day_of_week'] = df['day_of_week'].astype(cat_day_of_week) df['month'] = df['month'].astype(cat_month)
要按多个变量排序,咱们只须要传递一个列表来代替sort_values()。例如,按month和day_of_week排序。
df.sort_values(['month', 'day_of_week'])
按ustomer_id,month 和day_of_week排序。
df.sort_values(['customer_id', 'month', 'day_of_week'])
就这样,谢谢你的阅读。
请在个人Github上导出笔记本以获取源代码:https://github.com/BindiChen/machine-learning/blob/master/data-analysis/017-pandas-custom-sort/pandas-custom-sort.ipynb
原文连接:https://towardsdatascience.com/how-to-do-a-custom-sort-on-pandas-dataframe-ac18e7ea5320
欢迎关注磐创AI博客站:
http://panchuang.net/
sklearn机器学习中文官方文档:
http://sklearn123.com/
欢迎关注磐创博客资源汇总站:
http://docs.panchuang.net/