Pandalar veri çerçevesinde özel sıralama


93

Bir sütunun ay adını içerdiği python pandas veri çerçevem ​​var.

Sözlük kullanarak nasıl özel sıralama yapabilirim, örneğin:

custom_dict = {'March':0, 'April':1, 'Dec':3}  

1
Bir sütun ay adı içeriyor mu, ay adlarını (cevabım olarak) içeren bir sütun veya ay adları olarak sütun adları olan (eumiro'nun olarak) birçok sütun olduğu anlamına mı geliyor?
Andy Hayden

1
Kabul edilen yanıt güncel pd.Categoricaldeğildir ve kategorileri varsayılan olarak sıralı olarak yorumlamadığından teknik olarak da yanlıştır . Bu cevaba bakın .
cs95

Yanıtlar:


149

Pandas 0.15 , bunu yapmanın çok daha net bir yolunu sağlayan Kategorik Serisi'ni tanıttı :

Önce ay sütununu kategorik yapın ve kullanılacak sıralamayı belirtin.

In [21]: df['m'] = pd.Categorical(df['m'], ["March", "April", "Dec"])

In [22]: df  # looks the same!
Out[22]:
   a  b      m
0  1  2  March
1  5  6    Dec
2  3  4  April

Şimdi, ay sütununu sıraladığınızda, bu listeye göre sıralanacaktır:

In [23]: df.sort_values("m")
Out[23]:
   a  b      m
0  1  2  March
2  3  4  April
1  5  6    Dec

Not: Listede bir değer yoksa, NaN'ye dönüştürülür.


İlgilenenler için daha eski bir cevap ...

Bir ara seri oluşturabilirsiniz ve bunun set_indexüzerine:

df = pd.DataFrame([[1, 2, 'March'],[5, 6, 'Dec'],[3, 4, 'April']], columns=['a','b','m'])
s = df['m'].apply(lambda x: {'March':0, 'April':1, 'Dec':3}[x])
s.sort_values()

In [4]: df.set_index(s.index).sort()
Out[4]: 
   a  b      m
0  1  2  March
1  3  4  April
2  5  6    Dec

Daha yeni pandalarda belirtildiği gibi, Series'in replacebunu daha zarif bir şekilde yapmak için bir yöntemi vardır :

s = df['m'].replace({'March':0, 'April':1, 'Dec':3})

Küçük fark, sözlüğün dışında bir değer varsa bunun artmamasıdır (sadece aynı kalacaktır).


s = df['m'].replace({'March':0, 'April':1, 'Dec':3})2. satır için de çalışıyor - sadece benim gibi pandaları öğrenen herkesin hatırı için
kdauria

@kdauria iyi nokta! (Bunu yazdığımdan beri biraz zaman geçti!) kesinlikle en iyi seçeneği değiştirin, bir diğeri kullanmak .apply({'March':0, 'April':1, 'Dec':3}.get):) 0.15'te Kategorik Serilerimiz / sütunlarımız olacak, bu yüzden en iyi yol onu kullanmak ve sonra sıralama işe yarayacak.
Andy Hayden

@AndyHayden İkinci satırı 'değiştirme' yöntemiyle değiştirme özgürlüğünü aldım. Umarım sorun olmaz.
Faheem Mitha

@AndyHayden düzenlemesi reddedildi, ancak yine de makul bir değişiklik olduğunu düşünüyorum.
Faheem Mitha

7
df.sort_values("m")Yeni pandalarda (yerine df.sort("m")) kullandığınızdan emin olun , aksi takdirde bir AttributeError: 'DataFrame' object has no attribute 'sort';) elde edersiniz
beyin fırtınası

21

pandalar> = 1.1

Yakında argüman sort_valuesile kullanabileceksiniz key:

pd.__version__
# '1.1.0.dev0+2004.g8d10bfb6f'

custom_dict = {'March': 0, 'April': 1, 'Dec': 3} 
df

   a  b      m
0  1  2  March
1  5  6    Dec
2  3  4  April

df.sort_values(by=['m'], key=lambda x: x.map(custom_dict))

   a  b      m
0  1  2  March
2  3  4  April
1  5  6    Dec

keyArgüman girişi bir Serisi ve getiri Seri olarak sürer. Bu dizi dahili olarak sıralanmıştır ve sıralanan dizinler DataFrame girişini yeniden sıralamak için kullanılır. Sıralanacak birden fazla sütun varsa, anahtar işlevi sırayla her birine uygulanacaktır. Bkz . Anahtarlarla sıralama .


pandalar <= 1.0.X

Basit bir yöntem çıktısını kullanarak bir Series.mapve Series.argsortiçine indeksine dfkullanılarak DataFrame.iloc(argsort sıralanmış bir tamsayı pozisyonları ürettiği için); bir sözlüğünüz olduğu için; bu kolaylaşır.

df.iloc[df['m'].map(custom_dict).argsort()]

   a  b      m
0  1  2  March
2  3  4  April
1  5  6    Dec

Azalan sırada sıralamanız gerekiyorsa , eşlemeyi ters çevirin.

df.iloc[(-df['m'].map(custom_dict)).argsort()]

   a  b      m
1  5  6    Dec
2  3  4  April
0  1  2  March

Bunun yalnızca sayısal öğeler üzerinde çalıştığını unutmayın. Aksi takdirde, sort_valuesdizini kullanarak ve bu dizine erişerek bu sorunu çözmeniz gerekecektir :

df.loc[df['m'].map(custom_dict).sort_values(ascending=False).index]

   a  b      m
1  5  6    Dec
2  3  4  April
0  1  2  March

astype(Bu artık kullanımdan kaldırılmıştır) veya ile daha fazla seçenek mevcuttur pd.Categorical, ancak doğruordered=True çalışması için belirtmeniz gerekir .

# Older version,
# df['m'].astype('category', 
#                categories=sorted(custom_dict, key=custom_dict.get), 
#                ordered=True)
df['m'] = pd.Categorical(df['m'], 
                         categories=sorted(custom_dict, key=custom_dict.get), 
                         ordered=True)

Şimdi, basit bir sort_valuesarama hile yapacak:

df.sort_values('m')
 
   a  b      m
0  1  2  March
2  3  4  April
1  5  6    Dec

Kategorik sıralama groupby, çıktıları sıralarken de dikkate alınacaktır .


2
Bunu zaten vurguladınız, ancak başka birinin gözden geçirip gözden kaçırması durumunda tekrarlamak isterim: Pandalar ordered=NoneVarsayılan olarak Kategorik kümeler . Ayarlanmazsa, sıralama yanlış olacaktır veya V23'te bozulacaktır. Maks işlevi özellikle bir TypeError verir (Kategorik, maks. İşlem için sıralanmaz).
Dave Liu

17

Güncelleme

seçilen cevabı kullanın ! bu gönderiden daha yenidir ve yalnızca pandalarda sıralı verileri korumanın resmi yolu değildir, her açıdan daha iyidir, özellikler / performans vb. dahil. Aşağıda tarif ettiğim hacky yöntemimi kullanmayın.

Bu güncellemeyi sadece insanlar cevabımı yükseltmeye devam ettikleri için yazıyorum, ancak kesinlikle kabul edilenden daha kötü :)

Orijinal gönderi

Oyuna biraz geç kaldınız, ancak pandaların Series, DataFrame ve multiindex DataFrame nesnelerini rastgele işlevler kullanarak sıralayan bir işlev oluşturmanın bir yolu.

I faydalanmak df.iloc[index](göre konumuna göre bir serisi / DataFrame bir satır başvuran yöntem, df.locki referanslar değeri). Bunu kullanarak, bir dizi konumsal argüman döndüren bir işleve sahip olmamız yeterlidir:

def sort_pd(key=None,reverse=False,cmp=None):
    def sorter(series):
        series_list = list(series)
        return [series_list.index(i) 
           for i in sorted(series_list,key=key,reverse=reverse,cmp=cmp)]
    return sorter

Bunu, özel sıralama işlevleri oluşturmak için kullanabilirsiniz. Bu, Andy Hayden'ın cevabında kullanılan veri çerçevesi üzerinde çalışır:

df = pd.DataFrame([
    [1, 2, 'March'],
    [5, 6, 'Dec'],
    [3, 4, 'April']], 
  columns=['a','b','m'])

custom_dict = {'March':0, 'April':1, 'Dec':3}
sort_by_custom_dict = sort_pd(key=custom_dict.get)

In [6]: df.iloc[sort_by_custom_dict(df['m'])]
Out[6]:
   a  b  m
0  1  2  March
2  3  4  April
1  5  6  Dec

Bu, multiindex DataFrames ve Series nesnelerinde de çalışır:

months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']

df = pd.DataFrame([
    ['New York','Mar',12714],
    ['New York','Apr',89238],
    ['Atlanta','Jan',8161],
    ['Atlanta','Sep',5885],
  ],columns=['location','month','sales']).set_index(['location','month'])

sort_by_month = sort_pd(key=months.index)

In [10]: df.iloc[sort_by_month(df.index.get_level_values('month'))]
Out[10]:
                 sales
location  month  
Atlanta   Jan    8161
New York  Mar    12714
          Apr    89238
Atlanta   Sep    5885

sort_by_last_digit = sort_pd(key=lambda x: x%10)

In [12]: pd.Series(list(df['sales'])).iloc[sort_by_last_digit(df['sales'])]
Out[12]:
2    8161
0   12714
3    5885
1   89238

Bana göre bu temiz hissettiriyor, ancak optimize edilmiş pandaların işlemlerine güvenmek yerine yoğun bir şekilde python işlemlerini kullanıyor. Herhangi bir stres testi yapmadım ama bunun çok büyük DataFrame'lerde yavaşlayabileceğini tahmin ediyorum. Performansın sütun ekleme, sıralama ve silme işlemine kıyasla nasıl olduğundan emin değilsiniz. Kodu hızlandırmak için herhangi bir ipucu takdir edilecektir!


Bu, birden çok sütunu / dizini sıralamak için çalışır mı?
ConanG

evet, ancak seçilen cevap bunu yapmanın çok daha iyi bir yoludur. Birden fazla df.sort_index()dizininiz varsa, bunları tercih ettiğiniz sıralama düzenine göre düzenleyin ve ardından tüm dizin düzeylerini sıralamak için kullanın .
Michael Delgado

9
import pandas as pd
custom_dict = {'March':0,'April':1,'Dec':3}

df = pd.DataFrame(...) # with columns April, March, Dec (probably alphabetically)

df = pd.DataFrame(df, columns=sorted(custom_dict, key=custom_dict.get))

March, April, Dec sütunlarına sahip bir DataFrame döndürür


Bu, satırları sütundaki özel tahmine göre sıralamak yerine gerçek sütunları sıralar.
cs95
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.