Python 使用键参数按多列对数据帧排序

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”进行排序。因

我有一个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”进行排序。因此,这样的结果将是:

[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)
如果我试图通过熊猫排序应用此规则,我会遇到许多问题,包括:

  • pandas dataFrame.sort_values()函数与sort()函数一样接受用于排序的键,但键函数应该矢量化(根据pandas文档)。如果我尝试将排序键仅应用于列“一”,则会出现错误“TypeError:无法将序列转换为”
  • 使用Dataframe sort_values()方法时,它会将排序键应用于传入的所有列。这将不起作用,因为我想首先使用本机数字排序按列'two'排序

  • 我将如何按照上述方式对数据框进行排序?

    您可以将列
    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的顺序即可获得预期的排序顺序(看起来我在问题中的措辞有点不正确)。您找到解决方案了吗?接受的答案对我有效!