3

我在熊猫中有这些数据

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 和 Time 列排序,所以结果应该像

        '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 进行排序,然后重新索引数据。

我查看了多个类似的来源,但没有任何运气: Alphanumeric sort Sort dataframes

4

4 回答 4

5

使用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.

于 2018-12-20T14:49:01.503 回答
2

注意:此方法假设您希望按XsID形式的数字排序ABC-X

np.lexsort支持按多个系列排序,避免向数据框添加额外的系列。此示例按数字后缀排序,然后按:IDTime

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
于 2018-12-20T14:48:30.980 回答
1

I think you're looking for sort_values:

df.sort_values(['ID','Time'])

NB if you want CS1-11 to come after CS1-2 (which is not the standard string ordering) you may need to introduce a length column e.g.

df['len_ID'] = df['ID'].str.len()
df.sort_values(['len_ID', 'ID','Time'])
于 2018-12-20T14:43:17.940 回答
0

可以使用sorted对 ID 字符串的子集进行排序来实现所需的输出 - 请参阅此答案

pd.DataFrame(
    sorted(df.values, key=lambda x: int(x[0].split('-')[1])),
    columns=df.columns
)

注意这里的 lambda 函数正在获取 ID 中“-”之后的字符,转换为 int,然后对它们进行排序。这实现了“自然”排序。

       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
于 2018-12-20T15:55:10.690 回答