作者|B. Chen
編譯|VK
來源|Towards Data Science

Pandas DataFrame有一個內置方法sort_values(),可以根據給定的變數對值進行排序,該方法本身使用起來相當簡單,但是它不適用于自定義排序,例如,
-
t恤尺寸:XS、S、M、L和XL
-
月份:一月、二月、三月、四月等
-
星期幾:周一、周二、周三、周四、周五、周六和周日,
在本文中,我們將了解如何對Pandas DataFrame進行自定義排序,
請查看我的Github repo以獲取源代碼:https://github.com/BindiChen/machine-learning/blob/master/data-analysis/017-pandas-custom-sort/pandas-custom-sort.ipynb
問題
假設我們有一個關于服裝店的資料集:
df = pd.DataFrame({
'cloth_id': [1001, 1002, 1003, 1004, 1005, 1006],
'size': ['S', 'XL', 'M', 'XS', 'L', 'S'],
})

我們可以看到,每一塊布料都有一個尺寸值,資料應該按以下順序排序:
-
XS代表特大號
-
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將資料強制轉換為具有有序性的類別型別
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、1、2、3、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
參考參考
- [1] Pandas.CategoricalDtype API(https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.CategoricalDtype.html)
- [2] Pandas Categorical CategoricalDtype tutorial (https://pandas.pydata.org/pandas-docs/stable/user_guide/categorical.html#categorical-categoricaldtype)
原文鏈接: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/
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/197489.html
標籤:其他
上一篇:通過深層神經網路生成音樂
