自然地排序Pandas DataFrame

agf*_*997 15 python sorting natsort python-2.7 pandas

我有一个带有索引的pandas DataFrame,我想自然排序.Natsort似乎不起作用.在构建DataFrame之前对索引进行排序似乎没有帮助,因为我对DataFrame的操作似乎搞乱了进程中的排序.关于如何自然地采用指数的任何想法?

from natsort import natsorted
import pandas as pd

# An unsorted list of strings
a = ['0hr', '128hr', '72hr', '48hr', '96hr']
# Sorted incorrectly
b = sorted(a)
# Naturally Sorted 
c = natsorted(a)

# Use a as the index for a DataFrame
df = pd.DataFrame(index=a)
# Sorted Incorrectly
df2 = df.sort()
# Natsort doesn't seem to work
df3 = natsorted(df)

print(a)
print(b)
print(c)
print(df.index)
print(df2.index)
print(df3.index)
Run Code Online (Sandbox Code Playgroud)

Set*_*ton 24

接受的答案回答所提出的问题.我还想natsort在a中添加如何使用列DataFrame,因为这将是下一个问题.

In [1]: from pandas import DataFrame

In [2]: from natsort import natsorted, index_natsorted, order_by_index

In [3]: df = DataFrame({'a': ['a5', 'a1', 'a10', 'a2', 'a12'], 'b': ['b1', 'b1', 'b2', 'b2', 'b1']}, index=['0hr', '128hr', '72hr', '48hr', '96hr'])

In [4]: df
Out[4]: 
         a   b
0hr     a5  b1
128hr   a1  b1
72hr   a10  b2
48hr    a2  b2
96hr   a12  b1
Run Code Online (Sandbox Code Playgroud)

正如接受的答案所示,按索引排序非常简单:

In [5]: df.reindex(index=natsorted(df.index))
Out[5]: 
         a   b
0hr     a5  b1
48hr    a2  b2
72hr   a10  b2
96hr   a12  b1
128hr   a1  b1
Run Code Online (Sandbox Code Playgroud)

如果要以相同方式对列进行排序,则需要按照所需列重新排序的顺序对索引进行排序.natsort提供便利功能,index_natsortedorder_by_index做到这一点.

In [6]: df.reindex(index=order_by_index(df.index, index_natsorted(df.a)))
Out[6]: 
         a   b
128hr   a1  b1
48hr    a2  b2
0hr     a5  b1
72hr   a10  b2
96hr   a12  b1

In [7]: df.reindex(index=order_by_index(df.index, index_natsorted(df.b)))
Out[7]: 
         a   b
0hr     a5  b1
128hr   a1  b1
96hr   a12  b1
72hr   a10  b2
48hr    a2  b2
Run Code Online (Sandbox Code Playgroud)

如果要按任意数量的列(或列和索引)重新排序,可以使用zip(或itertools.izip在Python2上)指定多列的排序.给出的第一列是主要的排序列,然后是次要的,然后是第三列,等等......

In [8]: df.reindex(index=order_by_index(df.index, index_natsorted(zip(df.b, df.a))))
Out[8]: 
         a   b
128hr   a1  b1
0hr     a5  b1
96hr   a12  b1
48hr    a2  b2
72hr   a10  b2

In [9]: df.reindex(index=order_by_index(df.index, index_natsorted(zip(df.b, df.index))))
Out[9]: 
         a   b
0hr     a5  b1
96hr   a12  b1
128hr   a1  b1
48hr    a2  b2
72hr   a10  b2
Run Code Online (Sandbox Code Playgroud)

这是一个使用Categorical对象的替代方法,pandas开发人员告诉我这是执行此操作的"正确"方法.这需要(据我所见)pandas> = 0.16.0.目前,它只适用于列,但显然在pandas> = 0.17.0中,它们将添加CategoricalIndex允许此方法用于索引.

In [1]: from pandas import DataFrame

In [2]: from natsort import natsorted

In [3]: df = DataFrame({'a': ['a5', 'a1', 'a10', 'a2', 'a12'], 'b': ['b1', 'b1', 'b2', 'b2', 'b1']}, index=['0hr', '128hr', '72hr', '48hr', '96hr'])

In [4]: df.a = df.a.astype('category')

In [5]: df.a.cat.reorder_categories(natsorted(df.a), inplace=True, ordered=True)

In [6]: df.b = df.b.astype('category')

In [8]: df.b.cat.reorder_categories(natsorted(set(df.b)), inplace=True, ordered=True)

In [9]: df.sort('a')
Out[9]: 
         a   b
128hr   a1  b1
48hr    a2  b2
0hr     a5  b1
72hr   a10  b2
96hr   a12  b1

In [10]: df.sort('b')
Out[10]: 
         a   b
0hr     a5  b1
128hr   a1  b1
96hr   a12  b1
72hr   a10  b2
48hr    a2  b2

In [11]: df.sort(['b', 'a'])
Out[11]: 
         a   b
128hr   a1  b1
0hr     a5  b1
96hr   a12  b1
48hr    a2  b2
72hr   a10  b2
Run Code Online (Sandbox Code Playgroud)

Categorical对象允许您定义DataFrame要使用的排序顺序.调用时给出的元素reorder_categories必须是唯一的,因此调用set列"b".

我将它留给用户来决定它是否比reindex方法更好,因为它要求你在排序之前独立地对列数据进行排序DataFrame(尽管我认为第二种排序相当有效).


完全披露,我是natsort作者.


Erf*_*fan 14

使用sort_valuespandas >= 1.1.0

使用, 因为 中的新key参数,我们可以直接对列进行排序,而无需使用以下方法将其设置为索引:DataFrame.sort_valuespandas 1.1.0natsort.natsort_keygen

df = pd.DataFrame({
    "time": ['0hr', '128hr', '72hr', '48hr', '96hr'],
    "value": [10, 20, 30, 40, 50]
})

    time  value
0    0hr     10
1  128hr     20
2   72hr     30
3   48hr     40
4   96hr     50
Run Code Online (Sandbox Code Playgroud)
from natsort import natsort_keygen

df.sort_values(
    by="time",
    key=natsort_keygen()
)

    time  value
0    0hr     10
3   48hr     40
2   72hr     30
4   96hr     50
1  128hr     20
Run Code Online (Sandbox Code Playgroud)

  • 这个提议的解决方案有点“最大努力”解决方案 - `key=natsort_keygen()` 不会更省力吗? (2认同)

EdC*_*ica 9

如果要对df进行排序,只需对索引或数据进行排序,并直接分配给df的索引,而不是尝试将df作为arg传递,因为这会产生一个空列表:

In [7]:

df.index = natsorted(a)
df.index
Out[7]:
Index(['0hr', '48hr', '72hr', '96hr', '128hr'], dtype='object')
Run Code Online (Sandbox Code Playgroud)

请注意,df.index = natsorted(df.index)也有效

如果你将df作为arg传递它会产生一个空列表,在这种情况下,因为df是空的(没有列),否则它将返回排序的列,这不是你想要的:

In [10]:

natsorted(df)
Out[10]:
[]
Run Code Online (Sandbox Code Playgroud)

编辑

如果要对索引进行排序以便将数据与索引一起重新排序,请使用reindex:

In [13]:

df=pd.DataFrame(index=a, data=np.arange(5))
df
Out[13]:
       0
0hr    0
128hr  1
72hr   2
48hr   3
96hr   4
In [14]:

df = df*2
df
Out[14]:
       0
0hr    0
128hr  2
72hr   4
48hr   6
96hr   8
In [15]:

df.reindex(index=natsorted(df.index))
Out[15]:
       0
0hr    0
48hr   6
72hr   4
96hr   8
128hr  2
Run Code Online (Sandbox Code Playgroud)

请注意,您必须将结果分配给reindex新的df或自身,它不接受inplace参数.

  • 那你在这里问的是什么,你想在数据操作后对索引进行natsort?你可以使用`reindex`并在索引`df.reindex(index = natsorted(df.index))上调用`natsorted` (3认同)