【问题标题】:How to sort pandas DataFrame with a key?如何使用键对 Pandas DataFrame 进行排序?
【发布时间】:2021-09-08 14:51:20
【问题描述】:

我正在寻找一种对 pandas DataFrame 进行排序的方法。 pd.DataFrame.sort_values 不接受按键功能。我可以将其转换为列表并将密钥应用于sorted 函数,但这会很慢。另一种方式似乎与分类索引有关。我没有固定的行数,所以我不知道分类索引是否适用。

我已经给出了我想要排序什么样的数据的示例案例:

输入数据帧:

     clouds  fluff
0    {[}      1
1    >>>      2
2     {1      3
3    123      4
4  AAsda      5
5    aad      6

输出数据帧:

     clouds  fluff
0    >>>      2
1    {[}      1
2     {1      3
3    123      4
4    aad      6
5  AAsda      5

排序规则(优先级):

  • 第一个特殊字符(它们之间按 ascii 排序)

  • 接下来是数字

  • 接下来是小写字母(按字典顺序)

  • 接下来是大写字母(按字典顺序)

在普通的 python 中我会这样做

from functools import cmp_to_key

def ks(a, b):
    # "Not exactly this but similar"
    if a.isupper():
        return -1
    else:
        return 1

案例

sorted(['aa', 'AA', 'dd', 'DD'], key=cmp_to_key(ks))

答案:

['DD', 'AA', 'aa', 'dd']

你会如何处理 Pandas?

【问题讨论】:

  • @hellpanderr,是的,但我不知道如何将这个问题翻译成那样。
  • @Goyo,将示例从 Column 更改为 pd.DataFrame
  • GitHub 上有一个与此相关的issue

标签: python pandas


【解决方案1】:

从 pandas 1.1.0 开始,pandas.DataFrame.sort_values 接受类型为 callable 的参数 key

所以在这种情况下,我们将使用:

df.sort_values(by='clouds', key=kf)

kf 是在类型 Series 上运行的关键函数。接受并返回系列。

【讨论】:

    【解决方案2】:

    这可能有用,但仍然不确定特殊字符!他们真的可以排序吗!

    import pandas as pd
    
    a = [2, 'B', 'c', 1, 'a', 'b',3, 'C', 'A']
    
    df = pd.DataFrame({"a": a})
    df['upper'] = df['a'].str.isupper()
    df['lower'] = df['a'].str.islower()
    df['int'] = df['a'].apply(isinstance,args = [int])
    
    df2 = pd.concat([df[df['int'] == True].sort_values(by=['a']), 
               df[df['lower'] == True].sort_values(by=['a']),
               df[df['upper'] == True].sort_values(by=['a'])])
    
    print(df2)
    
       a    upper   lower   int
    3   1   NaN     NaN     True
    0   2   NaN     NaN     True
    6   3   NaN     NaN     True
    4   a   False   True    False
    5   b   False   True    False
    2   c   False   True    False
    8   A   True    False   False
    1   B   True    False   False
    7   C   True    False   False
    

    您也可以通过创建新的 True False 列一步完成!

    a = [2, 'B', 'c', 1, 'a', 'b',3, 'C', 'A']
    df = pd.DataFrame({"a": a})
    df2 = pd.concat([df[df['a'].apply(isinstance,args = [int])].sort_values(by=['a']), 
               df[df['a'].str.islower() == True].sort_values(by=['a']),
               df[df['a'].str.isupper() == True].sort_values(by=['a'])])
    
        a
    3   1
    0   2
    6   3
    4   a
    5   b
    2   c
    8   A
    1   B
    7   C
    

    【讨论】:

      【解决方案3】:

      这似乎有效:

      def sort_dataframe_by_key(dataframe: DataFrame, column: str, key: Callable) -> DataFrame:
          """ Sort a dataframe from a column using the key """
          sort_ixs = sorted(np.arange(len(dataframe)), key=lambda i: key(dataframe.iloc[i][column]))
          return DataFrame(columns=list(dataframe), data=dataframe.iloc[sort_ixs].values)
      
      

      它通过了测试:

      def test_sort_dataframe_by_key():
          dataframe = DataFrame([{'a': 1, 'b': 2, 'c': 3}, {'a': 2, 'b': 1, 'c': 1}, {'a': 3, 'b': 4, 'c': 0}])
          assert sort_dataframe_by_key(dataframe, column='a', key=lambda x: x).equals(
                 DataFrame([{'a': 1, 'b': 2, 'c': 3}, {'a': 2, 'b': 1, 'c': 1}, {'a': 3, 'b': 4, 'c': 0}]))
          assert sort_dataframe_by_key(dataframe, column='a', key=lambda x: -x).equals(
                 DataFrame([{'a': 3, 'b': 4, 'c': 0}, {'a': 2, 'b': 1, 'c': 1}, {'a': 1, 'b': 2, 'c': 3}]))
          assert sort_dataframe_by_key(dataframe, column='b', key=lambda x: -x).equals(
                 DataFrame([{'a': 3, 'b': 4, 'c': 0}, {'a': 1, 'b': 2, 'c': 3}, {'a': 2, 'b': 1, 'c': 1}]))
          assert sort_dataframe_by_key(dataframe, column='c', key=lambda x: x).equals(
                 DataFrame([{'a': 3, 'b': 4, 'c': 0}, {'a': 2, 'b': 1, 'c': 1}, {'a': 1, 'b': 2, 'c': 3}]))
      

      【讨论】:

        【解决方案4】:

        从熊猫 1.2.0 开始, 我这样做了

        import numpy as np
        import pandas as pd
        
        df = pd.DataFrame(['aa', 'dd', 'DD', 'AA'], columns=["data"])
        
        # This is the sorting rule
        rule = {
            "DD": 1,
            "AA": 10,
            "aa": 20,
            "dd": 30,
            }
        
        
        def particular_sort(series):
            """
            Must return one Series
            """
            return series.apply(lambda x: rule.get(x, 1000))
        
        
        new_df = df.sort_values(by=["data"], key=particular_sort)
        print(new_df)  # DD, AA, aa, dd
        

        当然,你也可以这样做,但可能很难理解,微笑

        new_df = df.sort_values(by=["data"], key=lambda x: x.apply(lambda y: rule.get(y, 1000)))
        print(new_df)  # DD, AA, aa, dd
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-04-20
          • 2018-07-03
          • 2016-09-14
          • 2022-01-21
          • 1970-01-01
          • 2018-08-22
          • 2021-03-21
          • 2022-08-15
          相关资源
          最近更新 更多