Естественная сортировка в пандах - PullRequest
0 голосов
/ 20 декабря 2018

У меня есть эти данные в 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 и 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, но я не могу заставить его работать.Либо я получаю ошибки, что в индекс входят дубликаты (в качестве индекса я использую идентификатор), либо он сортируется по строковым значениям.

Идентификатор здесь приведен только в качестве примера.Я не знаю, какой это будет формат, это может быть NUMBER-LETTER или NUMBER LETTER NUMBER.Мне просто нужно сравнить все числа как числа.Я посмотрел на "natsort", и это, кажется, правильно для массива.Поэтому я думаю, что можно использовать это для сортировки идентификатора и повторной индексации данных.

Я просмотрел несколько таких источников, но без особой удачи: Буквенно-цифровая сортировка Сортировка фреймов данных

Ответы [ 4 ]

0 голосов
/ 20 декабря 2018

Требуемый вывод можно получить с помощью sorted для сортировки по подмножеству строки идентификатора - см. этот ответ :

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

NB здесь лямбда-функция принимаетсимволы после '-' в 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
0 голосов
/ 20 декабря 2018

Примечание. Этот метод предполагает, что вы хотите выполнить числовую сортировку по X для ID с формы ABC-X.

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
0 голосов
/ 20 декабря 2018

Используйте 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

Предполагается, что столбец идентификатора соответствует шаблону "XXX-NUMBER".


Надежное решение будет включать использование модуля natsort, который выделяется при быстрой естественной сортировке.С помощью небольшого количества консистентной смазки мы сможем отсортировать ваши данные.

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.

0 голосов
/ 20 декабря 2018

Я думаю, что вы ищете sort_values:

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

NB, если вы хотите, чтобы CS1-11 следовало после CS1-2 (что не является стандартным порядком строк), которое вам может потребоваться ввестистолбец длины, например,

df['len_ID'] = df['ID'].str.len()
df.sort_values(['len_ID', 'ID','Time'])
...