如何對Pandas DataFrame進行自定義排序

做者|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()是按數字順序對數值數據排序,對對象數據按字母順序排序。

如下是兩種常見的解決方案:

  1. 爲自定義排序建立新列

  2. 使用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將數據強制轉換爲具備有序性的類別類型

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')

這樣效果更好。讓咱們來看看原理是什麼。

使用cat的codes屬性訪問

如今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()。例如,按monthday_of_week排序。

df.sort_values(['month', 'day_of_week'])

ustomer_idmonthday_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/

相關文章
相關標籤/搜索