Python 使用键参数按多列对数据帧排序
我有一个dataframe,一个包含以下列的pandas dataframe:Python 使用键参数按多列对数据帧排序,python,pandas,dataframe,sorting,Python,Pandas,Dataframe,Sorting,我有一个dataframe,一个包含以下列的pandas dataframe: df = pd.DataFrame([ [A2, 2], [B1, 1], [A1, 2], [A2, 1], [B1, 2], [A1, 1]], columns=['one','two']) 我希望主要按“2”列排序,然后按“1”列排序。对于二次排序,我想使用一个自定义排序规则,该规则将按字母字符[a-Z]和后面的数字[0-100]对列“one”进行排序。因
df = pd.DataFrame([
[A2, 2],
[B1, 1],
[A1, 2],
[A2, 1],
[B1, 2],
[A1, 1]],
columns=['one','two'])
我希望主要按“2”列排序,然后按“1”列排序。对于二次排序,我想使用一个自定义排序规则,该规则将按字母字符[a-Z]和后面的数字[0-100]对列“one”进行排序。因此,这样的结果将是:
[A1, 1]
[B1, 1]
[A2, 1]
[A1, 2]
[B1, 2]
[A2, 2]
在使用如下排序规则之前,我对类似于列“one”的字符串列表进行了排序:
def cusotm_sort(value):
return (value[0], int(value[1:]))
my_list.sort(key=custom_sort)
如果我试图通过熊猫排序应用此规则,我会遇到许多问题,包括:
我将如何按照上述方式对数据框进行排序?您可以将列
one
拆分为其组成部分,将它们作为列添加到数据框中,然后使用列two对它们进行排序。最后,删除临时列
>>> (df.assign(lhs=df['one'].str[0], rhs=df['one'].str[1:].astype(int))
.sort_values(['two', 'rhs', 'lhs'])
.drop(columns=['lhs', 'rhs']))
one two
5 A1 1
1 B1 1
3 A2 1
2 A1 2
4 B1 2
0 A2 2
使用str.extract
创建一些临时列,这些临时列基于1)字母(a-zA-Z]+)
和2)数字(\d+)
,然后删除它们:
df = pd.DataFrame([
['A2', 2],
['B1', 1],
['A1', 2],
['A2', 1],
['B1', 2],
['A1', 1]],
columns=['one','two'])
df['one-letter'] = df['one'].str.extract('([a-zA-Z]+)')
df['one-number'] = df['one'].str.extract('(\d+)')
df = df.sort_values(['two', 'one-number', 'one-letter']).drop(['one-letter', 'one-number'], axis=1)
df
Out[38]:
one two
5 A1 1
1 B1 1
3 A2 1
2 A1 2
4 B1 2
解决方案之一是使两列pd.Categorical并将预期顺序作为参数“categories”传递
但我有一些无法强制未知\意外值的要求,不幸的是,这就是pd.Categorical所做的。此外,None不作为类别支持,并自动强制
因此,我的解决方案是使用一个键以自定义排序顺序对多个列进行排序:
import pandas as pd
df = pd.DataFrame([
[A2, 2],
[B1, 1],
[A1, 2],
[A2, 1],
[B1, 2],
[A1, 1]],
columns=['one','two'])
def custom_sorting(col: pd.Series) -> pd.Series:
"""Series is input and ordered series is expected as output"""
to_ret = col
# apply custom sorting only to column one:
if col.name == "one":
custom_dict = {}
# for example ensure that A2 is first, pass items in sorted order here:
def custom_sort(value):
return (value[0], int(value[1:]))
ordered_items = list(col.unique())
ordered_items.sort(key=custom_sort)
# apply custom order first:
for index, item in enumerate(ordered_items):
custom_dict[item] = index
to_ret = col.map(custom_dict)
# default text sorting is about to be applied
return to_ret
# pass two columns to be sorted
df.sort_values(
by=["two", "one"],
ascending=True,
inplace=True,
key=custom_sorting,
)
print(df)
输出:
5 A1 1
3 A2 1
1 B1 1
2 A1 2
0 A2 2
4 B1 2
请注意,此解决方案可能很慢。谢谢您的帮助。这个答案有效,您只需在sort_values()调用中切换lhs和rhs的顺序即可获得预期的排序顺序(看起来我在问题中的措辞有点不正确)。您找到解决方案了吗?接受的答案对我有效!