pandas 中的自然排序
Natural sorting in pandas
我在 pandas
中有这个数据
data = [
['ID', 'Time', 'oneMissing', 'singleValue', 'empty', 'oneEmpty'],
['CS1-1', 1, 10000, None, None, 0],
['CS1-2', 2, 20000, 0.0, None, 0],
['CS1-1', 2, 30000, None, None, 0],
['CS1-2', 1, 10000, None, None, None],
['CS1-11', 1, None, 0.0, None, None],
['CS1-2', 3, 30000, None, None, None]
]
我尝试按 ID 和时间列排序,因此结果应该是这样的
'CS1-1', 1, 10000, None, None, 0
'CS1-1', 2, 30000, None, None, 0
'CS1-2', 1, 10000, None, None, None
'CS1-2', 2, 20000, 0.0, None, 0
'CS1-2', 3, 30000, None, None, None
'CS1-11', 1, None, 0.0, None, None
]
我正在使用 pandas 数据框进行排序,也尝试与 natsort 一起使用,但我无法让它工作。要么我收到索引包含重复项的错误(我使用 ID 作为索引),要么按字符串值排序。
这里的ID只是一个例子。我不知道它会是什么格式,它可能是 NUMBER-LETTER 或 NUMBER LETTER NUMBER。我只需要将所有数字作为一个数字进行比较。我查看了 "natsort" 并且这似乎对数组是正确的。所以我认为应该可以使用它来对 ID 进行排序,然后重新索引数据。
我已经查看了多个类似的来源,但没有任何运气:
我想你在找 sort_values
:
df.sort_values(['ID','Time'])
注意,如果您希望 CS1-11
出现在 CS1-2
之后(这不是标准的字符串排序),您可能需要引入一个长度列,例如
df['len_ID'] = df['ID'].str.len()
df.sort_values(['len_ID', 'ID','Time'])
注意:此方法假定您希望按 X
对 ID
的 ABC-X
.[=18 形式进行数字排序=]
np.lexsort
支持按多个系列排序,避免向数据框添加额外的系列。此示例按 ID
的 后缀 按数字排序, 然后 按 Time
:
排序
df = pd.DataFrame(data[1:], columns=data[0])
id_num = df['ID'].str.split('-').str[-1].astype(int)
df = df.iloc[np.lexsort((df['Time'], id_num))]
print(df)
ID Time oneMissing singleValue empty oneEmpty
0 CS1-1 1 10000.0 NaN None 0.0
2 CS1-1 2 30000.0 NaN None 0.0
3 CS1-2 1 10000.0 NaN None NaN
1 CS1-2 2 20000.0 0.0 None 0.0
5 CS1-2 3 30000.0 NaN None NaN
4 CS1-11 1 NaN 0.0 None NaN
使用str.extract
、sort_values
,然后使用索引重新索引df
。
idx = (df.assign(ID2=df.ID.str.extract(r'(\d+)$').astype(int))
.sort_values(['ID2', 'Time'])
.index)
df.iloc[idx]
ID Time oneMissing singleValue empty oneEmpty
0 CS1-1 1 10000.0 NaN None 0.0
2 CS1-1 2 30000.0 NaN None 0.0
3 CS1-2 1 10000.0 NaN None NaN
1 CS1-2 2 20000.0 0.0 None 0.0
5 CS1-2 3 30000.0 NaN None NaN
4 CS1-11 1 NaN 0.0 None NaN
这是假设您的 ID 列遵循模式 "XXX-NUMBER"。
一个万无一失的解决方案将涉及使用 natsort
模块,该模块擅长快速自然排序。稍加努力,我们就可以对您的数据进行 argsort。
from natsort import natsorted
idx, *_ = zip(*natsorted(
zip(df.index, df.ID, df.Time), key=lambda x: (x[1], x[2])))
df.iloc[list(idx)]
ID Time oneMissing singleValue empty oneEmpty
0 CS1-1 1 10000.0 NaN None 0.0
2 CS1-1 2 30000.0 NaN None 0.0
3 CS1-2 1 10000.0 NaN None NaN
1 CS1-2 2 20000.0 0.0 None 0.0
5 CS1-2 3 30000.0 NaN None NaN
4 CS1-11 1 NaN 0.0 None NaN
使用 PyPi 安装:pip install natsort
.
可以使用 sorted
对 ID 字符串的子集进行排序来实现所需的输出 - 请参阅 :
pd.DataFrame(
sorted(df.values, key=lambda x: int(x[0].split('-')[1])),
columns=df.columns
)
N.B。此处的 lambda 函数将 ID 中“-”之后的字符转换为 int,然后对这些字符进行排序。这实现了 'natural' 排序。
ID Time oneMissing singleValue empty oneEmpty
0 CS1-1 1 10000.0 NaN None 0.0
1 CS1-1 2 30000.0 NaN None 0.0
2 CS1-2 2 20000.0 0.0 None 0.0
3 CS1-2 1 10000.0 NaN None NaN
4 CS1-2 3 30000.0 NaN None NaN
5 CS1-11 1 NaN 0.0 None NaN
我在 pandas
中有这个数据data = [
['ID', 'Time', 'oneMissing', 'singleValue', 'empty', 'oneEmpty'],
['CS1-1', 1, 10000, None, None, 0],
['CS1-2', 2, 20000, 0.0, None, 0],
['CS1-1', 2, 30000, None, None, 0],
['CS1-2', 1, 10000, None, None, None],
['CS1-11', 1, None, 0.0, None, None],
['CS1-2', 3, 30000, None, None, None]
]
我尝试按 ID 和时间列排序,因此结果应该是这样的
'CS1-1', 1, 10000, None, None, 0
'CS1-1', 2, 30000, None, None, 0
'CS1-2', 1, 10000, None, None, None
'CS1-2', 2, 20000, 0.0, None, 0
'CS1-2', 3, 30000, None, None, None
'CS1-11', 1, None, 0.0, None, None
]
我正在使用 pandas 数据框进行排序,也尝试与 natsort 一起使用,但我无法让它工作。要么我收到索引包含重复项的错误(我使用 ID 作为索引),要么按字符串值排序。
这里的ID只是一个例子。我不知道它会是什么格式,它可能是 NUMBER-LETTER 或 NUMBER LETTER NUMBER。我只需要将所有数字作为一个数字进行比较。我查看了 "natsort" 并且这似乎对数组是正确的。所以我认为应该可以使用它来对 ID 进行排序,然后重新索引数据。
我已经查看了多个类似的来源,但没有任何运气:
我想你在找 sort_values
:
df.sort_values(['ID','Time'])
注意,如果您希望 CS1-11
出现在 CS1-2
之后(这不是标准的字符串排序),您可能需要引入一个长度列,例如
df['len_ID'] = df['ID'].str.len()
df.sort_values(['len_ID', 'ID','Time'])
注意:此方法假定您希望按 X
对 ID
的 ABC-X
.[=18 形式进行数字排序=]
np.lexsort
支持按多个系列排序,避免向数据框添加额外的系列。此示例按 ID
的 后缀 按数字排序, 然后 按 Time
:
df = pd.DataFrame(data[1:], columns=data[0])
id_num = df['ID'].str.split('-').str[-1].astype(int)
df = df.iloc[np.lexsort((df['Time'], id_num))]
print(df)
ID Time oneMissing singleValue empty oneEmpty
0 CS1-1 1 10000.0 NaN None 0.0
2 CS1-1 2 30000.0 NaN None 0.0
3 CS1-2 1 10000.0 NaN None NaN
1 CS1-2 2 20000.0 0.0 None 0.0
5 CS1-2 3 30000.0 NaN None NaN
4 CS1-11 1 NaN 0.0 None NaN
使用str.extract
、sort_values
,然后使用索引重新索引df
。
idx = (df.assign(ID2=df.ID.str.extract(r'(\d+)$').astype(int))
.sort_values(['ID2', 'Time'])
.index)
df.iloc[idx]
ID Time oneMissing singleValue empty oneEmpty
0 CS1-1 1 10000.0 NaN None 0.0
2 CS1-1 2 30000.0 NaN None 0.0
3 CS1-2 1 10000.0 NaN None NaN
1 CS1-2 2 20000.0 0.0 None 0.0
5 CS1-2 3 30000.0 NaN None NaN
4 CS1-11 1 NaN 0.0 None NaN
这是假设您的 ID 列遵循模式 "XXX-NUMBER"。
一个万无一失的解决方案将涉及使用 natsort
模块,该模块擅长快速自然排序。稍加努力,我们就可以对您的数据进行 argsort。
from natsort import natsorted
idx, *_ = zip(*natsorted(
zip(df.index, df.ID, df.Time), key=lambda x: (x[1], x[2])))
df.iloc[list(idx)]
ID Time oneMissing singleValue empty oneEmpty
0 CS1-1 1 10000.0 NaN None 0.0
2 CS1-1 2 30000.0 NaN None 0.0
3 CS1-2 1 10000.0 NaN None NaN
1 CS1-2 2 20000.0 0.0 None 0.0
5 CS1-2 3 30000.0 NaN None NaN
4 CS1-11 1 NaN 0.0 None NaN
使用 PyPi 安装:pip install natsort
.
可以使用 sorted
对 ID 字符串的子集进行排序来实现所需的输出 - 请参阅
pd.DataFrame(
sorted(df.values, key=lambda x: int(x[0].split('-')[1])),
columns=df.columns
)
N.B。此处的 lambda 函数将 ID 中“-”之后的字符转换为 int,然后对这些字符进行排序。这实现了 'natural' 排序。
ID Time oneMissing singleValue empty oneEmpty
0 CS1-1 1 10000.0 NaN None 0.0
1 CS1-1 2 30000.0 NaN None 0.0
2 CS1-2 2 20000.0 0.0 None 0.0
3 CS1-2 1 10000.0 NaN None NaN
4 CS1-2 3 30000.0 NaN None NaN
5 CS1-11 1 NaN 0.0 None NaN