Цифры с дефисами или цепочки цифр с дефисами

Мне нужно создать pandas DataFrame, в котором есть столбец, заполненный номерами с дефисом. Единственный способ, который я мог придумать, - это использовать строки. Все это работало нормально, пока мне не потребовалось отсортировать их, чтобы вернуть в порядок после перегруппировки. Проблема в том, что строки сортируются следующим образом:

['100-200','1000-1100','1100-1200','200-300']

Это явно не так, как я хочу. Я хочу, чтобы это было отсортировано по номерам. Как мне заставить это работать? Я готов все изменить. Лучше всего было бы сохранить строку с дефисом в виде целого числа или числа с плавающей запятой, но я не уверен, как это сделать.


person Wesley Bowman    schedule 31.12.2013    source источник


Ответы (2)


Вы можете использовать sorted, чтобы создать новый порядок для индекса, а затем выполнить сортировку (переупорядочение) с помощью df.take:

import pandas as pd

df = pd.DataFrame({'foo':['100-200','1000-1100','1100-1200','200-300']})
order = sorted(range(len(df)),
               key=lambda idx: map(int, df.ix[idx, 'foo'].split('-')))
df = df.take(order)
print(df)

дает

         foo
0    100-200
3    200-300
1  1000-1100
2  1100-1200

Это похоже на решение @ 275365, но обратите внимание, что сортировка выполняется по range(len(df)), а не по строкам. Строки используются только в параметре key для определения порядка, в котором range(len(df)) следует переставлять.


Использование sorted отлично работает, если DataFrame небольшой. Вы можете повысить производительность, когда DataFrame имеет средний размер (например, несколько сотен строк на моем компьютере), используя вместо этого numpy.argsort:

import pandas as pd
import numpy as np

df = pd.DataFrame({'foo':['100-200','1000-1100','1100-1200','200-300']*100})

arr = df['foo'].map(lambda item: map(int, item.split('-'))).values
order = np.argsort(arr)
df = df.take(order)

В качестве альтернативы вы можете разделить свой строковый столбец на два столбца с целыми значениями, а затем использовать df.sort:

import pandas as pd

df = pd.DataFrame({'foo':['100-200','1000-1100','1100-1200','200-300']})

df[['start', 'end']] = df['foo'].apply(lambda val: pd.Series(map(int, val.split('-'))))
df.sort(['start', 'end'], inplace=True)
print(df)

дает

         foo  start   end
0    100-200    100   200
3    200-300    200   300
1  1000-1100   1000  1100
2  1100-1200   1100  1200
person unutbu    schedule 31.12.2013
comment
Использование вашего решения с numpy в нем, похоже, работает для меня. По какой-то причине использование sort или sorted дает мне ошибку TypeError с недопустимым ключевым словом key. Новая проблема заключается в том, что мне нужно сначала отсортировать по одному столбцу, а затем по столбцу с переносом, а не связываться с первым столбцом. - person Wesley Bowman; 01.01.2014
comment
Закончилось использованием вашего последнего решения, а затем просто удалением начального и конечного столбцов после их сортировки. Это позволило мне отсортировать все 3 столбца на месте. Спасибо! - person Wesley Bowman; 01.01.2014

Вы можете попробовать что-то вроде этого:

>>> t = ['100-200','1000-1100','1100-1200','200-300']
>>> t.sort(key=lambda x: [int(y) for y in x.split('-')])
>>> t
['100-200', '200-300', '1000-1100', '1100-1200']

Это позволит вам сортировать по целым числам, и если дефис существует, он будет сортировать сначала по первому целому числу в списке ключей, а затем по второму. Если дефиса нет, вы выполните сортировку только по целочисленному эквиваленту строки:

>>> t = ['100-200','1000-1100','1100-1200','200-300', '100']
>>> t.sort(key=lambda x: [int(y) for y in x.split('-')])
>>> t
['100', '100-200', '200-300', '1000-1100', '1100-1200']

Если у вас есть какие-либо float эквиваленты в любых строках, просто измените int на float следующим образом:

>>> t = ['100-200.3','1000.5-1100','1100.76-1200','200-300.75', '100.35']
>>> t.sort(key=lambda x: [float(y) for y in x.split('-')])
>>> t
['100-200.3', '100.35', '200-300.75', '1000.5-1100', '1100.76-1200']
person Justin O Barber    schedule 31.12.2013