按自定义方式排序Pandas数据框。

3

我已经尝试了很多方法来按照自己的方式对DataFrame列进行排序。但是无法正确地完成此操作。因此,请参考给定的代码,并告诉我需要做哪些额外的语法才能完成此任务。

df = pd.DataFrame({'TC': {0: '1-1.1', 1: '1-1.2', 2: '1-10.1', 3: '1-10.2', 4: '1-2.1', 5: '1-2.1', 6: '1-2.2', 7: '1-20.1', 8: '1-20.2', 9: '1-3.1'}, 'Case': {0: 'A', 1: 'B', 2: 'C', 3: 'D', 4: 'E', 5: 'F', 6: 'G', 7: 'H', 8: 'I', 9: 'J'}})
df.sort_values(["TC"], ascending=[True])
print (df)

该代码未产生期望输出。我需要按照以下方式对数据框进行排序。 enter image description here
3个回答

5
你可以提取数字并形成一个元组,然后对该序列进行排序,并使用其索引对原始数据框进行重新索引。
>>> df.reindex(
        df['TC'].str.extractall('(\d+)')
                .unstack().astype(int)
                .agg(tuple, 1).sort_values()
                .index
    )

       TC Case
0   1-1.1    A
1   1-1.2    B
4   1-2.1    E
5   1-2.1    F
6   1-2.2    G
9   1-3.1    J
2  1-10.1    C
3  1-10.2    D
7  1-20.1    H
8  1-20.2    I

您还可以在sort_values中使用key参数:

>>> df.sort_values('TC', 
        key=lambda ser:
           ser.str.extractall('(\d+)')
              .unstack()
              .astype(int).agg(tuple, 1)
    )

如果一个ID总是由三部分组成,可以使用Series.str.split对非数字字符进行分割,并使用expand=True参数,而不是使用extractall,因此无需使用unstack来处理:
>>> df.sort_values('TC', 
         key=lambda series:
             series.str.split(r'\D+', expand=True)
                   .astype(int).agg(tuple,1)
    )

时间:

>>> %timeit df.reindex(df['TC'].str.extractall('(\d+)').unstack().astype(int).agg(tuple, 1).sort_values().index)
2.95 ms ± 40.1 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

>>> %timeit df.sort_values('TC', key=lambda ser: ser.str.extractall('(\d+)').unstack().astype(int).agg(tuple, 1))
2.91 ms ± 32.5 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

>>> %timeit df.sort_values('TC', key=lambda series:series.str.split(r'\D+', expand=True).astype(int).agg(tuple,1))
1.6 ms ± 5.88 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

1

我会这样做。我认为这样会更快。

df["range"] = df["TC"].apply(lambda x: [float(y) for y in x.split("-")])
df = df.sort_values(["range"], ascending=True).drop(["range"], axis="columns")

编辑: 既然您要求处理1-1.2格式的范围变成1_1_2的情况,我会这样做:

df["range"] = df["TC"].apply(lambda x: tuple(x.split("_")))
df["range"] = df["range"].apply(lambda x: [float(x[0]), float("{}.{}".format(x[1], x[2]))])
df = df.sort_values(["range"], ascending=True).drop(["range"], axis="columns")

你让它变得简单了,如果数据形式为“1_2_1”而不是“1-2.1”,那么代码应该怎么写? - OO7
1
好吧,事实并非如此,但我仍需要添加一行额外的代码来解析列并将其转换为所需的格式,就像编辑部分所示。 - Akash

0

我已经编写了一个sort()函数,可以解决您的问题。

import pandas as pd
df = pd.DataFrame({'TC': {0: '1-1.1', 1: '1-1.2', 2: '1-10.1', 3: '1-10.2', 4: '1-2.1', 5: '1-2.1', 6: '1-2.2', 7: '1-20.1', 8: '1-20.2', 9: '1-3.1'}, 'Case': {0: 'A', 1: 'B', 2: 'C', 3: 'D', 4: 'E', 5: 'F', 6: 'G', 7: 'H', 8: 'I', 9: 'J'}})


def sort(df):
    listTC=[]
    for i in df['TC']:
        listTC.append(float(i[2:]))
        
    df1=pd.DataFrame(list(zip(listTC,list(df['Case']))),columns=['TC','Case'])
    
    df_f=df1.sort_values(by=['TC'])
    
    listTC_final=[]
    for i in df_f['TC']:
        listTC_final.append('1-'+str(i))
        
    df_Final=pd.DataFrame(list(zip(listTC_final,list(df_f['Case']))),columns=['TC','Case'])
    
    return df_Final

print(sort(df))

如果还有任何问题,请告诉我。 谢谢


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接