自然排序 Pandas DataFrame
Naturally sorting Pandas DataFrame
我有一个 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)
如果你想对 df 进行排序,只需对索引或数据进行排序并直接分配给 df 的索引,而不是尝试将 df 作为 arg 传递,因为那样会产生一个空列表:
In [7]:
df.index = natsorted(a)
df.index
Out[7]:
Index(['0hr', '48hr', '72hr', '96hr', '128hr'], dtype='object')
注意 df.index = natsorted(df.index)
也有效
如果您将 df 作为 arg 传递,它会产生一个空列表,在这种情况下是因为 df 是空的(没有列),否则它将 return 对列进行排序,这不是您想要的:
In [10]:
natsorted(df)
Out[10]:
[]
编辑
如果要对索引进行排序以便数据与索引一起重新排序,请使用 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
请注意,您必须将 reindex
的结果分配给新的 df 或自身,它不接受 inplace
参数。
既然 pandas
在 sort_values
和 sort_index
中都支持 key
,您现在应该参考 并将所有赞成票发送到那里现在是正确答案。
我会在这里留下我的答案,以帮助那些坚持使用旧 pandas
版本的人,或者出于对历史的好奇。
回答了所问的问题。我还想添加如何在 DataFrame
中的列上使用 natsort
,因为这将是下一个问题。
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
如 所示,按索引排序非常简单:
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
如果您想以相同的方式对列进行排序,则需要按照所需列的重新排序顺序对索引进行排序。 natsort
提供了方便的函数 index_natsorted
和 order_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
如果要按任意数量的列(或列和索引)重新排序,可以使用zip
(或Python2上的itertools.izip
)指定排序在多个列上。给出的第一列将是主要排序列,然后是次要列,然后是第三列,等等...
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
这是使用 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
Categorical
对象允许您定义要使用的 DataFrame
的排序顺序。调用 reorder_categories
时给出的元素必须是唯一的,因此调用 set
用于列“b”。
我让用户决定这是否比 reindex
方法更好,因为它要求您在 DataFrame
中排序之前独立地对列数据进行排序(尽管我想象一下第二种排序是相当有效的)。
完全公开,我是 natsort
作者。
将 sort_values
用于 pandas >= 1.1.0
使用 DataFrame.sort_values
中的新 key
参数,因为 pandas 1.1.0
, we can directly sort a column without setting it as an index using natsort.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
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
我有一个 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)
如果你想对 df 进行排序,只需对索引或数据进行排序并直接分配给 df 的索引,而不是尝试将 df 作为 arg 传递,因为那样会产生一个空列表:
In [7]:
df.index = natsorted(a)
df.index
Out[7]:
Index(['0hr', '48hr', '72hr', '96hr', '128hr'], dtype='object')
注意 df.index = natsorted(df.index)
也有效
如果您将 df 作为 arg 传递,它会产生一个空列表,在这种情况下是因为 df 是空的(没有列),否则它将 return 对列进行排序,这不是您想要的:
In [10]:
natsorted(df)
Out[10]:
[]
编辑
如果要对索引进行排序以便数据与索引一起重新排序,请使用 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
请注意,您必须将 reindex
的结果分配给新的 df 或自身,它不接受 inplace
参数。
既然 pandas
在 sort_values
和 sort_index
中都支持 key
,您现在应该参考 并将所有赞成票发送到那里现在是正确答案。
我会在这里留下我的答案,以帮助那些坚持使用旧 pandas
版本的人,或者出于对历史的好奇。
DataFrame
中的列上使用 natsort
,因为这将是下一个问题。
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
如
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
如果您想以相同的方式对列进行排序,则需要按照所需列的重新排序顺序对索引进行排序。 natsort
提供了方便的函数 index_natsorted
和 order_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
如果要按任意数量的列(或列和索引)重新排序,可以使用zip
(或Python2上的itertools.izip
)指定排序在多个列上。给出的第一列将是主要排序列,然后是次要列,然后是第三列,等等...
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
这是使用 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
Categorical
对象允许您定义要使用的 DataFrame
的排序顺序。调用 reorder_categories
时给出的元素必须是唯一的,因此调用 set
用于列“b”。
我让用户决定这是否比 reindex
方法更好,因为它要求您在 DataFrame
中排序之前独立地对列数据进行排序(尽管我想象一下第二种排序是相当有效的)。
完全公开,我是 natsort
作者。
将 sort_values
用于 pandas >= 1.1.0
使用 DataFrame.sort_values
中的新 key
参数,因为 pandas 1.1.0
, we can directly sort a column without setting it as an index using natsort.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
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