Not
Bu gönderi aşağıdaki şekilde yapılandırılacaktır:
- OP'de ortaya konan sorular tek tek ele alınacaktır.
- Her soru için, bu problemi çözmek ve beklenen sonucu elde etmek için geçerli olan bir veya daha fazla yöntem gösterilecektir.
Notlar (buna çok benzer), ek işlevsellik, uygulama ayrıntıları ve eldeki konuyla ilgili diğer bilgileri öğrenmekle ilgilenen okuyucular için dahil edilecektir. Bu notlar, belgeleri inceleyerek ve çeşitli belirsiz özellikleri ortaya çıkararak ve benim (kuşkusuz sınırlı) deneyimlerime dayanarak derlendi.
Tüm kod örnekleri pandalar v0.23.4, python3.7 üzerinde oluşturulmuş ve test edilmiştir . Bir şey net değilse veya gerçeklere göre yanlışsa ya da kullanım alanınıza uygun bir çözüm bulamadıysanız, lütfen bir düzenleme önermekten, yorumlarda açıklama istemekten veya yeni bir soru açmaktan çekinmeyin. .
İşte sık sık tekrar ziyaret edeceğimiz bazı yaygın deyimlere (bundan böyle Dört Deyim olarak anılacaktır) bir giriş.
DataFrame.loc
- Etikete göre seçim için genel bir çözüm (+ pd.IndexSlice
dilimleri içeren daha karmaşık uygulamalar için)
DataFrame.xs
- Seri / Veri Çerçevesinden belirli bir kesiti çıkarın.
DataFrame.query
- Dilimleme ve / veya filtreleme işlemlerini dinamik olarak belirtin (yani, dinamik olarak değerlendirilen bir ifade olarak. Bazı senaryolar için diğerlerinden daha uygundur. Ayrıca MultiIndexes üzerinde sorgulama için belgelerin bu bölümüne bakın .
Kullanılarak oluşturulan bir maske ile Boole dizini oluşturma MultiIndex.get_level_values
( Index.isin
özellikle birden çok değerle filtreleme yaparken genellikle ile bağlantılı olarak ). Bu aynı zamanda bazı durumlarda oldukça kullanışlıdır.
Belirli bir duruma neyin uygulanabileceğini daha iyi anlamak için çeşitli dilimleme ve filtreleme problemlerine Dört Deyim açısından bakmak faydalı olacaktır. Tüm deyimlerin her durumda eşit derecede iyi çalışmayacağını (eğer varsa) anlamak çok önemlidir. Bir deyim aşağıda bir soruna potansiyel çözüm olarak listelenmemişse, bu, deyimin o soruna etkili bir şekilde uygulanamayacağı anlamına gelir.
Soru 1
Düzey "bir" de "a" içeren satırları nasıl seçerim?
col
one two
a t 0
u 1
v 2
w 3
loc
Çoğu durumda geçerli olan genel amaçlı bir çözüm olarak kullanabilirsiniz :
df.loc[['a']]
Bu noktada, eğer alırsan
TypeError: Expected tuple, got str
Bu, pandaların eski bir sürümünü kullandığınız anlamına gelir. Yükseltmeyi düşünün! Aksi takdirde kullanın df.loc[('a', slice(None)), :]
.
Alternatif olarak, xs
tek bir kesit çıkardığımız için burayı kullanabilirsiniz . Not levels
ve axis
(makul varsayılan burada varsayılabilir) argümanlar.
df.xs('a', level=0, axis=0, drop_level=False)
# df.xs('a', drop_level=False)
Burada, sonuçtaki "bir" düzeyinin (dilimlediğimiz düzey) düşmesini drop_level=False
önlemek için argüman gereklidir xs
.
Yine burada başka bir seçenek kullanmak query
:
df.query("one == 'a'")
Dizinin bir adı yoksa, sorgu dizenizi olarak değiştirmeniz gerekir "ilevel_0 == 'a'"
.
Son olarak, şunu kullanarak get_level_values
:
df[df.index.get_level_values('one') == 'a']
# If your levels are unnamed, or if you need to select by position (not label),
# df[df.index.get_level_values(0) == 'a']
Ek olarak, çıktıda "bir" seviyesini nasıl düşürebilirim?
col
two
t 0
u 1
v 2
w 3
Bu, aşağıdakilerden biri kullanılarak kolayca yapılabilir
df.loc['a'] # Notice the single string argument instead the list.
Veya,
df.xs('a', level=0, axis=0, drop_level=True)
# df.xs('a')
drop_level
Argümanı atlayabileceğimize dikkat edin (varsayılan olarak olduğu True
varsayılır).
Not
Filtrelenmiş bir DataFrame'in, DataFrame dışarı yazdırılırken gösterilmese bile tüm düzeylere sahip olabileceğini fark edebilirsiniz. Örneğin,
v = df.loc[['a']]
print(v)
col
one two
a t 0
u 1
v 2
w 3
print(v.index)
MultiIndex(levels=[['a', 'b', 'c', 'd'], ['t', 'u', 'v', 'w']],
labels=[[0, 0, 0, 0], [0, 1, 2, 3]],
names=['one', 'two'])
Şunları kullanarak bu seviyelerden kurtulabilirsiniz MultiIndex.remove_unused_levels
:
v.index = v.index.remove_unused_levels()
print(v.index)
MultiIndex(levels=[['a'], ['t', 'u', 'v', 'w']],
labels=[[0, 0, 0, 0], [0, 1, 2, 3]],
names=['one', 'two'])
Soru 1b
Düzey "iki" de "t" değerine sahip tüm satırları nasıl dilimleyebilirim?
col
one two
a t 0
b t 4
t 8
d t 12
Sezgisel olarak, aşağıdakileri içeren bir şey istersiniz slice()
:
df.loc[(slice(None), 't'), :]
It Just Works! ™ Ama hantal. pd.IndexSlice
Burada API'yi kullanarak daha doğal bir dilimleme sözdizimini kolaylaştırabiliriz .
idx = pd.IndexSlice
df.loc[idx[:, 't'], :]
Bu çok çok daha temiz.
Not Sütunların
sonundaki dilim neden :
gerekli? Bunun nedeni, loc
her iki eksen ( axis=0
veya
axis=1
) boyunca seçmek ve dilimlemek için kullanılabilmesidir . Dilimlemenin hangi eksende yapılacağını açıkça belirtmeden işlem belirsizleşir. Dilimleme ile ilgili belgelerdeki büyük kırmızı kutuya bakın .
Herhangi bir belirsizlik gölgesini kaldırmak istiyorsanız, loc
bir axis
parametre kabul eder :
df.loc(axis=0)[pd.IndexSlice[:, 't']]
axis
Parametre olmadan (yani, sadece yaparak df.loc[pd.IndexSlice[:, 't']]
), dilimlemenin sütunlarda olduğu varsayılır ve KeyError
bu durumda a yükseltilecektir.
Bu, dilimleyicilerde belgelenmiştir . Bununla birlikte, bu yazının amacı için, tüm eksenleri açıkça belirteceğiz.
İle xs
, öyle
df.xs('t', axis=0, level=1, drop_level=False)
İle query
, öyle
df.query("two == 't'")
# Or, if the first level has no name,
# df.query("ilevel_1 == 't'")
Ve son olarak, get_level_values
yapabilirsin
df[df.index.get_level_values('two') == 't']
# Or, to perform selection by position/integer,
# df[df.index.get_level_values(1) == 't']
Hepsi aynı etkiye.
soru 2
Düzey "bir" de "b" ve "d" öğelerine karşılık gelen satırları nasıl seçebilirim?
col
one two
b t 4
u 5
v 6
w 7
t 8
d w 11
t 12
u 13
v 14
w 15
Loc kullanarak, bu da benzer bir şekilde bir liste belirleyerek yapılır.
df.loc[['b', 'd']]
Seçimi "b" ve "d" nin yukarıdaki sorunu çözmek için ayrıca kullanabilirsiniz query
:
items = ['b', 'd']
df.query("one in @items")
# df.query("one == @items", parser='pandas')
# df.query("one in ['b', 'd']")
# df.query("one == ['b', 'd']", parser='pandas')
Not
Evet, varsayılan ayrıştırıcıdır 'pandas'
, ancak bu sözdiziminin geleneksel olarak python olmadığını vurgulamak önemlidir. Pandalar ayrıştırıcısı, ifadeden biraz farklı bir ayrıştırma ağacı oluşturur. Bu, bazı işlemleri daha sezgisel hale getirmek için yapılır. Daha fazla bilgi için lütfen
pd.eval () kullanarak pandalarda Dinamik İfade Değerlendirmesi hakkındaki yazımı okuyun .
Ve get_level_values
+ ile Index.isin
:
df[df.index.get_level_values("one").isin(['b', 'd'])]
Soru 2b
Düzey "iki" de "t" ve "w" ye karşılık gelen tüm değerleri nasıl elde ederim?
col
one two
a t 0
w 3
b t 4
w 7
t 8
d w 11
t 12
w 15
İle loc
bu sadece ile birlikte mümkündür pd.IndexSlice
.
df.loc[pd.IndexSlice[:, ['t', 'w']], :]
Birinci kolon :
içinde pd.IndexSlice[:, ['t', 'w']]
vasıtasıyla ilk seviye boyunca dilim. Sorgulanan seviyenin derinliği arttıkça, her seviye için dilimlenecek şekilde daha fazla dilim belirtmeniz gerekecektir. Bununla birlikte, dilimlenenin ötesinde daha fazla seviye belirlemenize gerek yoktur .
İle query
bu
items = ['t', 'w']
df.query("two in @items")
# df.query("two == @items", parser='pandas')
# df.query("two in ['t', 'w']")
# df.query("two == ['t', 'w']", parser='pandas')
İle get_level_values
ve Index.isin
(yukarıdakine benzer):
df[df.index.get_level_values('two').isin(['t', 'w'])]
Soru 3
Bir enine kesiti, yani indeks için belirli değerlere sahip tek bir satırı nereden alabilirim df
? Özellikle, ('c', 'u')
tarafından verilen kesitini nasıl alırım
col
one two
c u 9
Kullanım loc
tuşlarının bir demet belirterek:
df.loc[('c', 'u'), :]
Veya,
df.loc[pd.IndexSlice[('c', 'u')]]
Not
Bu noktada, PerformanceWarning
şuna benzer bir ile karşılaşabilirsiniz:
PerformanceWarning: indexing past lexsort depth may impact performance.
Bu sadece dizininizin sıralanmadığı anlamına gelir. Pandalar, optimum arama ve erişim için sıralanan dizine bağlıdır (bu durumda, dizgi değerleriyle uğraştığımız için sözlükbilimsel olarak). Hızlı bir düzeltme, DataFrame'inizi kullanarak önceden sıralamak olacaktır DataFrame.sort_index
. Bu tür birden çok sorguyu art arda yapmayı planlıyorsanız, bu özellikle performans açısından istenir:
df_sort = df.sort_index()
df_sort.loc[('c', 'u')]
Ayrıca MultiIndex.is_lexsorted()
dizinin sıralı olup olmadığını kontrol etmek için de kullanabilirsiniz . Bu işlev True
veya False
buna göre döner . Ek bir sıralama adımının gerekli olup olmadığını belirlemek için bu işlevi çağırabilirsiniz.
İle xs
, bu yine, diğer tüm argümanlar uygun varsayılan değerlerine ayarlanmış olarak, ilk argüman olarak tek bir demeti iletmektir:
df.xs(('c', 'u'))
İle query
işler biraz hantal hale geliyor:
df.query("one == 'c' and two == 'u'")
Şimdi bunu genellemenin nispeten zor olacağını görebilirsiniz. Ancak bu özel sorun için hala sorun yok.
Birden çok seviyeye yayılan erişimlerle get_level_values
, yine de kullanılabilir, ancak önerilmez:
m1 = (df.index.get_level_values('one') == 'c')
m2 = (df.index.get_level_values('two') == 'u')
df[m1 & m2]
Soru 4
Nasıl karşılık gelen iki satır seçerim ('c', 'u')
ve ('a', 'w')
?
col
one two
c u 9
a w 3
Bununla birlikte loc
, bu hala şu kadar basit:
df.loc[[('c', 'u'), ('a', 'w')]]
# df.loc[pd.IndexSlice[[('c', 'u'), ('a', 'w')]]]
İle query
, kesitlerinizi ve seviyelerinizi yineleyerek dinamik olarak bir sorgu dizisi oluşturmanız gerekecektir:
cses = [('c', 'u'), ('a', 'w')]
levels = ['one', 'two']
# This is a useful check to make in advance.
assert all(len(levels) == len(cs) for cs in cses)
query = '(' + ') or ('.join([
' and '.join([f"({l} == {repr(c)})" for l, c in zip(levels, cs)])
for cs in cses
]) + ')'
print(query)
# ((one == 'c') and (two == 'u')) or ((one == 'a') and (two == 'w'))
df.query(query)
% 100 TAVSİYE ETMEYİN! Ama mümkün.
Soru 5
Düzey "bir" de "a" veya "iki" düzeyindeki "t" ye karşılık gelen tüm satırları nasıl alabilirim?
col
one two
a t 0
u 1
v 2
w 3
b t 4
t 8
d t 12
loc
Doğruluğu sağlarken ve yine de kod netliğini korurken bunu yapmak aslında çok zordur . df.loc[pd.IndexSlice['a', 't']]
yanlış olarak yorumlanır df.loc[pd.IndexSlice[('a', 't')]]
(yani, bir kesit seçme). pd.concat
Her etiketi ayrı ayrı ele almak için bir çözüm düşünebilirsiniz :
pd.concat([
df.loc[['a'],:], df.loc[pd.IndexSlice[:, 't'],:]
])
col
one two
a t 0
u 1
v 2
w 3
t 0 # Does this look right to you? No, it isn't!
b t 4
t 8
d t 12
Ancak satırlardan birinin kopyalandığını fark edeceksiniz. Bunun nedeni, bu satırın hem dilimleme koşullarını karşılaması hem de iki kez görünmesidir. Bunun yerine yapmanız gerekecek
v = pd.concat([
df.loc[['a'],:], df.loc[pd.IndexSlice[:, 't'],:]
])
v[~v.index.duplicated()]
Ancak DataFrame'iniz doğası gereği yinelenen endeksler içeriyorsa (istediğiniz), o zaman bu onları tutmayacaktır. Çok dikkatli kullanın .
Bununla query
aptalca basit:
df.query("one == 'a' or two == 't'")
Bununla birlikte get_level_values
, bu hala basit, ancak o kadar zarif değil:
m1 = (df.index.get_level_values('one') == 'a')
m2 = (df.index.get_level_values('two') == 't')
df[m1 | m2]
Soru 6
Belirli kesitleri nasıl dilimleyebilirim? "A" ve "b" için, "u" ve "v" alt düzeylerine sahip tüm satırları seçmek istiyorum ve "d" için, alt düzeyi "w" olan satırları seçmek istiyorum.
col
one two
a u 1
v 2
b u 5
v 6
d w 11
w 15
Bu, Dört Deyimin uygulanabilirliğini anlamaya yardımcı olmak için eklediğim özel bir durumdur - bu, dilimleme çok özel olduğundan ve herhangi bir gerçek modeli takip etmediğinden hiçbirinin etkili bir şekilde çalışmayacağı bir durumdur .
Genellikle, bunun gibi dilimleme problemleri, anahtarlarının bir listesini açıkça iletmeyi gerektirir loc
. Bunu yapmanın bir yolu şudur:
keys = [('a', 'u'), ('a', 'v'), ('b', 'u'), ('b', 'v'), ('d', 'w')]
df.loc[keys, :]
Bazı yazımları kaydetmek istiyorsanız, "a", "b" ve alt seviyelerini dilimlemek için bir kalıp olduğunu fark edeceksiniz, böylece dilimleme görevini iki kısma ayırabiliriz ve concat
sonuç:
pd.concat([
df.loc[(('a', 'b'), ('u', 'v')), :],
df.loc[('d', 'w'), :]
], axis=0)
"A" ve "b" için dilimleme (('a', 'b'), ('u', 'v'))
özelliği, indekslenen aynı alt düzeyler her düzey için aynı olduğundan biraz daha temizdir .
Soru 7
Düzey "iki" deki değerlerin 5'ten büyük olduğu tüm satırları nasıl elde ederim?
col
one two
b 7 4
9 5
c 7 10
d 6 11
8 12
8 13
6 15
Bu kullanılarak yapılabilir query
,
df2.query("two > 5")
Ve get_level_values
.
df2[df2.index.get_level_values('two') > 5]
Not
Bu örneğe benzer şekilde, bu yapıları kullanarak herhangi bir keyfi koşula göre filtre uygulayabiliriz. Genel olarak, hatırlamak faydalıdır loc
ve xs
süre, etiket bazlı endeksleme için özel olan query
ve
get_level_values
filtreleme için genel koşullu maskeleri oluşturmak için faydalıdır.
Bonus soru
Ya bir MultiIndex
sütunu dilimlemem gerekirse ?
Aslında, buradaki çoğu çözüm, küçük değişikliklerle birlikte sütunlara da uygulanabilir. Düşünmek:
np.random.seed(0)
mux3 = pd.MultiIndex.from_product([
list('ABCD'), list('efgh')
], names=['one','two'])
df3 = pd.DataFrame(np.random.choice(10, (3, len(mux))), columns=mux3)
print(df3)
one A B C D
two e f g h e f g h e f g h e f g h
0 5 0 3 3 7 9 3 5 2 4 7 6 8 8 1 6
1 7 7 8 1 5 9 8 9 4 3 0 3 5 0 2 3
2 8 1 3 3 3 7 0 1 9 9 0 4 7 3 2 7
Bunlar, sütunlarla çalışmasını sağlamak için Dört Deyimde yapmanız gereken aşağıdaki değişikliklerdir.
Birlikte dilimlemek için loc
kullanın
df3.loc[:, ....] # Notice how we slice across the index with `:`.
veya,
df3.loc[:, pd.IndexSlice[...]]
xs
Uygun şekilde kullanmak için bir argüman iletmeniz yeterlidir axis=1
.
Doğrudan kullanarak sütun seviyesi değerlerine erişebilirsiniz df.columns.get_level_values
. Daha sonra şunun gibi bir şey yapmanız gerekecek
df.loc[:, {condition}]
Burada {condition}
kullanılarak inşa edilen bazı koşulları temsil eder columns.get_level_values
.
Kullanmak query
için tek seçeneğiniz sırasını değiştirmek, dizini sorgulamak ve yeniden sıralamaktır:
df3.T.query(...).T
Önerilmez, diğer 3 seçenekten birini kullanın.
level
tartışmasını bilmiyordumIndex.isin
!