2017-04-04 12 views
5

dataframe sütuna 'A' tarafından tanımlanan 'X' grupla dfBir sütun tarafından tanımlanan bölümler arasında nasıl sıralama yapabilirim, ancak bölümleri oldukları yerde bırakabilirim?

df = pd.DataFrame(dict(
     A=list('XXYYXXYY'), 
     B=range(8, 0, -1) 
    )) 

print(df) 

    A B 
0 X 8 
1 X 7 
2 Y 6 
3 Y 5 
4 X 4 
5 X 3 
6 Y 2 
7 Y 1 

düşünün beklediğimden [3, 4, 7, 8] için [8, 7, 4, 3] sıralamak istiyorum. Ancak, o satırları oldukları yerde bırakmak istiyorum.

A B 
5 X 3 <-- Notice all X are in same positions 
4 X 4 <-- However, `[3, 4, 7, 8]` have shifted 
7 Y 1 
6 Y 2 
1 X 7 <-- 
0 X 8 <-- 
3 Y 5 
2 Y 6 
+0

Bunun için gerçekten çok üzgünüm. Bu cevapta, daha genel bir çözüm (nokta ve '.eq (1)' ile) eklemek istiyorsanız, yorum ekleyeceğim, ancak gerekli olduğunu düşünmüyorsunuz. (Yanılıyor muyum? Ya da değil?) Bu nedenle cevabımı ekledim. Ama sanırım bana sorun olduğunu biliyorsun, o zaman bu cevabı kaldırırım. Gelecekte bu problemin, özellikle benim ve senin çözümün arasındaki ince sınır varsa, lütfen beni haberdar et. Çok üzgünüm. – jezrael

+0

Ben bunu çok düşünüyorum ve asıl problemim senin için sorun olduğunu bilmiyorum. Ama küçük kibarlığım var. Yorumda bağlantıdaki cevabın nasıl değiştiği konusunda bana yardımcı olabilir misiniz? 'Kredi başka bir kullanıcıya aittir' cümlesi nasıl yazılır? '(Ya da farklı bir şey gerekli (benim ingilizcem ne yazık ki, ne yazık ki)). Teşekkürler. – jezrael

cevap

3

Sen DataFrame yeniden düzenlemek için, sonra istediğiniz yeni endeks sipariş geri almak reindex kullanmak transform kullanabilirsiniz:

# Use transform to return the new ordered index values. 
new_idx = df.groupby('A')['B'].transform(lambda grp: grp.sort_values().index) 

# Reindex. 
df = df.reindex(new_idx.rename(None)) 

İki satırı int üstünden birleştirebilirsiniz o uzun bir çizgi, eğer istenirse.

çıkan çıkışı: Eski indeksi maintaing umurumda değil, sen doğrudan transform den yeniden atamak anlamına

A B 
5 X 3 
4 X 4 
7 Y 1 
6 Y 2 
1 X 7 
0 X 8 
3 Y 5 
2 Y 6 

Not:

df['B'] = df.groupby('A')['B'].transform(lambda grp: grp.sort_values()) 

verir:

A B 
0 X 3 
1 X 4 
2 Y 1 
3 Y 2 
4 X 7 
5 X 8 
6 Y 5 
7 Y 6 
+0

Bunun işe yaramasını beklemiyordum! Endeksin otomatik olarak yeniden hizalanmasını bekledim. 'dönüştürme' bunu yapmaz! Bilmek çok güzel.Şimdi bunu test etmek zorundayım :-) – piRSquared

+0

Ayrıca, daha büyük veri kümelerinde olduğu gibi performans göstermesini de beklemiyordum. Bunu daha önce numpy ile nasıl yapacağım konusunda daha fazla düşünüyorum. – piRSquared

2

Bu kadar verimli bir şekilde nasıl çözüleceğimi çözmenin tek yolu iki kez sıralamak ve bir kez gevşemek oldu.

v = df.values 

# argsort just first column with kind='mergesort' to preserve subgroup order 
a1 = v[:, 0].argsort(kind='mergesort') 

# Fill in an un-sort array to unwind the `a1` argsort 
a_ = np.empty_like(a1) 
a_[a1] = np.arange(len(a1)) 

# argsort by both columns... not exactly what I want, yet. 
a2 = np.lexsort(v.T[::-1]) 

# Sort with `a2` then unwind the first layer with `a_` 
pd.DataFrame(v[a2][a_], df.index[a2][a_], df.columns) 

    A B 
5 X 3 
4 X 4 
7 Y 1 
6 Y 2 
1 X 7 
0 X 8 
3 Y 5 
2 Y 6 

Test

Kod

def np_intra_sort(df): 
    v = df.values 
    a1 = v[:, 0].argsort(kind='mergesort') 
    a_ = np.empty_like(a1) 
    a_[a1] = np.arange(len(a1)) 
    a2 = np.lexsort(v.T[::-1]) 
    return pd.DataFrame(v[a2][a_], df.index[a2][a_], df.columns) 

def pd_intra_sort(df): 

    def sub_sort(x): 
     return x.sort_values().index 

    idx = df.groupby('A').B.transform(sub_sort).values 

    return df.reindex(idx) 

Küçük veriler

Enter image description here

Büyük veri

df = pd.DataFrame(dict(
     A=list('XXYYXXYY') * 10000, 
     B=range(8 * 10000, 0, -1) 
    )) 

Enter image description here

İlgili konular