नोट
इस पोस्ट को निम्न तरीके से संरचित किया जाएगा:
- ओपी में पूछे गए सवालों को एक-एक करके संबोधित किया जाएगा
- प्रत्येक प्रश्न के लिए, इस समस्या को हल करने और अपेक्षित परिणाम प्राप्त करने के लिए लागू एक या एक से अधिक तरीकों का प्रदर्शन किया जाएगा।
नोट एस (बहुत कुछ इस तरह) पाठकों के लिए अतिरिक्त कार्यक्षमता, कार्यान्वयन विवरण और विषय के लिए अन्य जानकारी सरसरी जानकारी के साथ शामिल किया जाएगा। ये नोट्स डॉक्स को परिमार्जन और विभिन्न अस्पष्ट विशेषताओं को उजागर करने के माध्यम से संकलित किए गए हैं, और मेरे अपने (संयुक्त रूप से सीमित) अनुभव से।
सभी कोड नमूनों ने पांडा v0.23.4, python3.7 पर बनाया और परीक्षण किया है । यदि कुछ स्पष्ट नहीं है, या तथ्यात्मक रूप से गलत है, या यदि आपको अपने उपयोग के मामले में कोई समाधान नहीं मिला है, तो कृपया एक संपादन का सुझाव देने के लिए स्वतंत्र महसूस करें, टिप्पणियों में स्पष्टीकरण का अनुरोध करें, या एक नया प्रश्न खोलें, .... जैसा कि लागू हो ।
यहां कुछ सामान्य मुहावरों का परिचय दिया गया है (इसलिए फोर आइडियम्स के रूप में संदर्भित) हम बार-बार आएंगे
DataFrame.loc
- लेबल द्वारा चयन के लिए एक सामान्य समाधान (+ pd.IndexSlice
अधिक जटिल अनुप्रयोगों के लिए स्लाइस शामिल)
DataFrame.xs
- एक श्रृंखला / DataFrame से एक विशेष क्रॉस सेक्शन निकालें।
DataFrame.query
- स्लाइसिंग और / या फ़िल्टरिंग ऑपरेशन को गतिशील रूप से निर्दिष्ट करें (अर्थात, एक अभिव्यक्ति के रूप में जिसका मूल्यांकन गतिशील रूप से किया जाता है। दूसरों की तुलना में कुछ परिदृश्यों पर अधिक लागू होता है। इसके अलावा डॉक्स के इस अनुभाग को मल्टीआईंडेक्स पर क्वेरी करने के लिए देखें।
एक मुखौटा के साथ बूलियन अनुक्रमण का उपयोग करके उत्पन्न MultiIndex.get_level_values
(अक्सर के साथ संयोजन के रूप में Index.isin
, खासकर जब कई मूल्यों के साथ फ़िल्टरिंग)। यह भी कुछ परिस्थितियों में काफी उपयोगी है।
एक बेहतर समझ हासिल करने के लिए चार मुहावरों के संदर्भ में विभिन्न स्लाइसिंग और फ़िल्टरिंग समस्याओं पर ध्यान देना फायदेमंद होगा जो किसी दिए गए स्थिति पर लागू हो सकते हैं। यह समझना बहुत महत्वपूर्ण है कि सभी मुहावरे हर परिस्थिति में (यदि बिल्कुल भी) समान रूप से अच्छे से काम करेंगे। अगर किसी मुहावरे को नीचे दी गई समस्या के संभावित समाधान के रूप में सूचीबद्ध नहीं किया गया है, तो इसका मतलब है कि मुहावरे को उस समस्या पर प्रभावी रूप से लागू नहीं किया जा सकता है।
प्रश्न 1
मैं "स्तर" "एक" वाली पंक्तियों का चयन कैसे करूं?
col
one two
a t 0
u 1
v 2
w 3
आप loc
अधिकांश स्थितियों के लिए एक सामान्य उद्देश्य समाधान के रूप में उपयोग कर सकते हैं :
df.loc[['a']]
इस बिंदु पर, यदि आप प्राप्त करते हैं
TypeError: Expected tuple, got str
इसका मतलब है कि आप पांडा के पुराने संस्करण का उपयोग कर रहे हैं। उन्नयन पर विचार करें! अन्यथा, उपयोग करें df.loc[('a', slice(None)), :]
।
वैकल्पिक रूप से, आप xs
यहां उपयोग कर सकते हैं , क्योंकि हम एक एकल क्रॉस सेक्शन निकाल रहे हैं। ध्यान दें levels
और axis
तर्क (उचित चूक यहां मान ली जा सकती है)।
df.xs('a', level=0, axis=0, drop_level=False)
# df.xs('a', drop_level=False)
यहां, परिणाम में "स्तर" को छोड़ने के स्तर drop_level=False
को रोकने के लिए तर्क की आवश्यकता है xs
(जिस स्तर पर हम फिसल गए थे)।
फिर भी एक और विकल्प यहाँ उपयोग कर रहा है query
:
df.query("one == 'a'")
यदि इंडेक्स में कोई नाम नहीं है, तो आपको अपनी क्वेरी स्ट्रिंग को बदलने की आवश्यकता होगी "ilevel_0 == 'a'"
।
अंत में, का उपयोग कर 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']
इसके अतिरिक्त, मैं आउटपुट में "एक" स्तर कैसे गिरा सकता हूं?
col
two
t 0
u 1
v 2
w 3
इसे आसानी से इस्तेमाल किया जा सकता है
df.loc['a'] # Notice the single string argument instead the list.
या,
df.xs('a', level=0, axis=0, drop_level=True)
# df.xs('a')
ध्यान दें कि हम drop_level
तर्क को छोड़ सकते हैं (इसे True
डिफ़ॉल्ट रूप से माना जाता है )।
नोट
आप देख सकते हैं कि फ़िल्टर किए गए DataFrame में अभी भी सभी स्तर हो सकते हैं, भले ही वे DataFrame को प्रिंट करते समय नहीं दिखाते हों। उदाहरण के लिए,
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'])
आप इन स्तरों से छुटकारा पा सकते हैं 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'])
प्रश्न 1 बी
मैं मूल्य "t" के साथ सभी पंक्तियों को "दो" स्तर पर कैसे काटूं?
col
one two
a t 0
b t 4
t 8
d t 12
सहज रूप से, आप कुछ शामिल करना चाहते हैं slice()
:
df.loc[(slice(None), 't'), :]
इट जस्ट वर्क्स! ™ लेकिन यह क्लंकी है। हम pd.IndexSlice
यहां एपीआई का उपयोग करके अधिक प्राकृतिक स्लाइसिंग सिंटैक्स की सुविधा प्रदान कर सकते हैं।
idx = pd.IndexSlice
df.loc[idx[:, 't'], :]
यह बहुत, बहुत क्लीनर है।
नोट कॉलम के पार
अनुगामी टुकड़ा क्यों :
आवश्यक है? इसका कारण यह है, loc
दोनों अक्षों ( axis=0
या
axis=1
) के साथ चयन और स्लाइस करने के लिए इस्तेमाल किया जा सकता है । स्पष्ट रूप से यह स्पष्ट किए बिना कि धुरी को किस अक्ष पर किया जाना है, ऑपरेशन अस्पष्ट हो जाता है। स्लाइसिंग पर प्रलेखन में बड़ा लाल बॉक्स देखें ।
यदि आप अस्पष्टता के किसी भी शेड को दूर करना चाहते हैं, तो loc
एक axis
पैरामीटर को स्वीकार करता है :
df.loc(axis=0)[pd.IndexSlice[:, 't']]
axis
पैरामीटर के बिना (यानी, बस कर df.loc[pd.IndexSlice[:, 't']]
), स्लाइसिंग को कॉलम पर माना जाता है, और KeyError
इस परिस्थिति में उठाया जाएगा।
यह स्लाइसर में प्रलेखित है । इस पोस्ट के उद्देश्य के लिए, हालांकि, हम स्पष्ट रूप से सभी कुल्हाड़ियों को निर्दिष्ट करेंगे।
के साथ xs
, यह है
df.xs('t', axis=0, level=1, drop_level=False)
के साथ query
, यह है
df.query("two == 't'")
# Or, if the first level has no name,
# df.query("ilevel_1 == 't'")
और अंत में get_level_values
, आप कर सकते हैं
df[df.index.get_level_values('two') == 't']
# Or, to perform selection by position/integer,
# df[df.index.get_level_values(1) == 't']
सभी एक ही प्रभाव के लिए।
प्रश्न 2
मैं आइटम "बी" और "डी" के स्तर "एक" के अनुरूप पंक्तियों का चयन कैसे कर सकता हूं?
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
लोक का उपयोग करते हुए, यह एक सूची निर्दिष्ट करके इसी तरह से किया जाता है।
df.loc[['b', 'd']]
"बी" और "डी" के चयन की उपरोक्त समस्या को हल करने के लिए, आप भी उपयोग कर सकते हैं 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')
नोट
हाँ, डिफ़ॉल्ट पार्सर है 'pandas'
, लेकिन इस वाक्यविन्यास को उजागर करना महत्वपूर्ण है पारंपरिक रूप से अजगर नहीं है। पांडस पार्सर अभिव्यक्ति से थोड़ा अलग पार्स पेड़ उत्पन्न करता है। यह निर्दिष्ट करने के लिए कुछ कार्यों को अधिक सहज बनाने के लिए किया जाता है। अधिक जानकारी के लिए, कृपया pd.eval () का उपयोग करके पांडा में डायनामिक अभिव्यक्ति मूल्यांकन पर मेरी पोस्ट पढ़ें
।
और, get_level_values
+ के साथ Index.isin
:
df[df.index.get_level_values("one").isin(['b', 'd'])]
प्रश्न 2 बी
मुझे "t" और "w" स्तर "दो" के अनुरूप सभी मान कैसे प्राप्त होंगे?
col
one two
a t 0
w 3
b t 4
w 7
t 8
d w 11
t 12
w 15
इसके साथ loc
, यह केवल संयोजन के साथ संभव है pd.IndexSlice
।
df.loc[pd.IndexSlice[:, ['t', 'w']], :]
पहले पेट :
में pd.IndexSlice[:, ['t', 'w']]
साधन प्रथम स्तर के पार काट करने के लिए। जैसे-जैसे स्तर की गहराई बढ़ती जा रही है, आपको और अधिक स्लाइस निर्दिष्ट करने की आवश्यकता होगी, एक स्तर के पार स्लाइस किया जा रहा है। हालांकि, आपको कटा हुआ होने के अलावा और अधिक स्तरों को निर्दिष्ट करने की आवश्यकता नहीं होगी ।
के साथ query
, यह है
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')
साथ get_level_values
और Index.isin
(ऊपर के समान):
df[df.index.get_level_values('two').isin(['t', 'w'])]
प्रश्न 3
मैं एक क्रॉस सेक्शन को कैसे प्राप्त कर सकता हूं, अर्थात, इंडेक्स के लिए एक विशिष्ट मान रखने वाली एकल पंक्ति df
? विशेष रूप से, मैं ('c', 'u')
द्वारा दिए गए क्रॉस सेक्शन को कैसे पुनः प्राप्त करूं
col
one two
c u 9
loc
चाबियों का एक समूह निर्दिष्ट करके उपयोग करें :
df.loc[('c', 'u'), :]
या,
df.loc[pd.IndexSlice[('c', 'u')]]
नोट
इस बिंदु पर, आप PerformanceWarning
इस तरह दिख सकते हैं:
PerformanceWarning: indexing past lexsort depth may impact performance.
इसका मतलब यह है कि आपका सूचकांक क्रमबद्ध नहीं है। पैंडा इष्टतम खोज और पुनर्प्राप्ति के लिए अनुक्रमित होने पर (इस मामले में, शाब्दिक रूप से, हम स्ट्रिंग मान के साथ काम कर रहे हैं) पर निर्भर करता है। एक त्वरित फिक्स अग्रिम में उपयोग करके अपने डेटाफ़्रेम को सॉर्ट करना होगा DataFrame.sort_index
। यह विशेष रूप से एक प्रदर्शन के दृष्टिकोण से वांछनीय है, अगर आप मिलकर ऐसे कई प्रश्न करते हैं:
df_sort = df.sort_index()
df_sort.loc[('c', 'u')]
आप यह MultiIndex.is_lexsorted()
जांचने के लिए भी उपयोग कर सकते हैं कि सूचकांक अनुक्रमित है या नहीं। यह फ़ंक्शन रिटर्न True
या False
तदनुसार। आप इस फ़ंक्शन को यह निर्धारित करने के लिए कॉल कर सकते हैं कि अतिरिक्त सॉर्टिंग चरण की आवश्यकता है या नहीं।
इसके साथ xs
, यह फिर से पहले तर्क के रूप में एकल टपल को पारित कर रहा है, अन्य सभी तर्कों के साथ उनके उचित चूक के लिए सेट किया गया है:
df.xs(('c', 'u'))
के साथ query
, चीजें थोड़ी भद्दी हो जाती हैं:
df.query("one == 'c' and two == 'u'")
अब आप देख सकते हैं कि इसे सामान्य बनाना अपेक्षाकृत कठिन है। लेकिन फिर भी इस विशेष समस्या के लिए ठीक है।
कई स्तरों पर फैले एक्सेस के साथ, get_level_values
अभी भी उपयोग किया जा सकता है, लेकिन अनुशंसित नहीं है:
m1 = (df.index.get_level_values('one') == 'c')
m2 = (df.index.get_level_values('two') == 'u')
df[m1 & m2]
प्रश्न 4
मैं करने के लिए इसी दो पंक्तियों का चयन कैसे करूं ('c', 'u')
, और ('a', 'w')
?
col
one two
c u 9
a w 3
इसके साथ loc
, यह अभी भी उतना ही सरल है:
df.loc[[('c', 'u'), ('a', 'w')]]
# df.loc[pd.IndexSlice[[('c', 'u'), ('a', 'w')]]]
इसके साथ query
, आपको अपने क्रॉस सेक्शन और स्तरों पर पुनरावृति करके गतिशील रूप से एक क्वेरी स्ट्रिंग उत्पन्न करने की आवश्यकता होगी:
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% मत करो! लेकिन यह संभव है।
प्रश्न 5
मैं "स्तर" एक "एक" या "t" स्तर "दो" में संगत सभी पंक्तियों को कैसे प्राप्त कर सकता हूं?
col
one two
a t 0
u 1
v 2
w 3
b t 4
t 8
d t 12
यह वास्तव में loc
शुद्धता सुनिश्चित करते हुए और अभी भी कोड स्पष्टता बनाए रखने के साथ करना बहुत मुश्किल है । df.loc[pd.IndexSlice['a', 't']]
यह गलत है, इसकी व्याख्या की जाती है df.loc[pd.IndexSlice[('a', 't')]]
(जैसे, क्रॉस सेक्शन का चयन करना)। आप pd.concat
प्रत्येक लेबल को अलग से संभालने के साथ एक समाधान के बारे में सोच सकते हैं :
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
लेकिन आप देखेंगे कि एक पंक्ति दोहराई गई है। ऐसा इसलिए है क्योंकि उस पंक्ति ने दोनों स्लाइसिंग शर्तों को संतुष्ट किया है, और इसलिए दो बार दिखाई दिया। आपको इसके बजाय करने की आवश्यकता होगी
v = pd.concat([
df.loc[['a'],:], df.loc[pd.IndexSlice[:, 't'],:]
])
v[~v.index.duplicated()]
लेकिन अगर आपके डेटाफ़्रेम में अंतर्निहित डुप्लिकेट इंडेक्स (जो आप चाहते हैं) शामिल हैं, तो यह उन्हें बनाए नहीं रखेगा। अत्यधिक सावधानी के साथ उपयोग करें ।
इसके साथ query
, यह मूर्खतापूर्ण सरल है:
df.query("one == 'a' or two == 't'")
इसके साथ get_level_values
, यह अभी भी सरल है, लेकिन उतना सुरुचिपूर्ण नहीं है:
m1 = (df.index.get_level_values('one') == 'a')
m2 = (df.index.get_level_values('two') == 't')
df[m1 | m2]
प्रश्न 6
मैं विशिष्ट क्रॉस सेक्शन का टुकड़ा कैसे कर सकता हूं? "ए" और "बी" के लिए, मैं उप-स्तरों "यू" और "वी" के साथ सभी पंक्तियों का चयन करना चाहूंगा, और "डी" के लिए, मैं उप-स्तर "डब्ल्यू" के साथ पंक्तियों का चयन करना चाहूंगा।
col
one two
a u 1
v 2
b u 5
v 6
d w 11
w 15
यह एक विशेष मामला है जिसे मैंने चार मुहावरों की प्रयोज्यता को समझने में मदद करने के लिए जोड़ा है - यह एक ऐसा मामला है जहां उनमें से कोई भी प्रभावी ढंग से काम नहीं करेगा, क्योंकि स्लाइसिंग बहुत विशिष्ट है, और किसी भी वास्तविक पैटर्न का पालन नहीं करता है।
आमतौर पर, इस तरह की समस्याओं को कम करने के लिए कुंजी की सूची को स्पष्ट रूप से पारित करने की आवश्यकता होगी loc
। ऐसा करने का एक तरीका यह है:
keys = [('a', 'u'), ('a', 'v'), ('b', 'u'), ('b', 'v'), ('d', 'w')]
df.loc[keys, :]
यदि आप कुछ टाइपिंग को सहेजना चाहते हैं, तो आप यह पहचानेंगे कि "a", "b" और इसके उपशीर्षों को स्लाइस करने का एक पैटर्न है, इसलिए हम स्लाइसिंग कार्य को दो भागों में विभाजित कर सकते हैं और concat
परिणाम:
pd.concat([
df.loc[(('a', 'b'), ('u', 'v')), :],
df.loc[('d', 'w'), :]
], axis=0)
"ए" और "बी" के लिए स्लाइसिंग विनिर्देश थोड़ा साफ है (('a', 'b'), ('u', 'v'))
क्योंकि समान उप-स्तरों को अनुक्रमित किया जा रहा है जो प्रत्येक स्तर के लिए समान हैं।
प्रश्न 7
मुझे उन सभी पंक्तियों को कैसे प्राप्त करना चाहिए जहां स्तर "दो" में मान 5 से अधिक हैं?
col
one two
b 7 4
9 5
c 7 10
d 6 11
8 12
8 13
6 15
यह प्रयोग करके किया जा सकता है query
,
df2.query("two > 5")
और get_level_values
।
df2[df2.index.get_level_values('two') > 5]
नोट
इस उदाहरण के समान, हम इन निर्माणों का उपयोग करके किसी भी मनमानी स्थिति के आधार पर फ़िल्टर कर सकते हैं। सामान्य तौर पर, यह है कि याद करने के लिए उपयोगी है loc
और xs
लेबल आधारित अनुक्रमण के लिए विशेष रूप से कर रहे हैं, जबकि query
और
get_level_values
छानने के लिए सामान्य सशर्त मास्क के निर्माण के लिए सहायक होते हैं।
बोनस प्रश्न
क्या होगा यदि मुझे एक MultiIndex
कॉलम को स्लाइस करने की आवश्यकता है ?
दरअसल, यहां ज्यादातर समाधान छोटे बदलावों के साथ ही कॉलम पर भी लागू होते हैं। विचार करें:
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
ये निम्नलिखित बदलाव हैं, जिन्हें आपको स्तंभों के साथ काम करने के लिए चार मुहावरों के लिए करना होगा।
के साथ टुकड़ा करने के लिए loc
, का उपयोग करें
df3.loc[:, ....] # Notice how we slice across the index with `:`.
या,
df3.loc[:, pd.IndexSlice[...]]
xs
उपयुक्त के रूप में उपयोग करने के लिए , बस एक तर्क पास करें axis=1
।
आप सीधे उपयोग करके कॉलम स्तर मानों तक पहुँच सकते हैं df.columns.get_level_values
। फिर आपको कुछ ऐसा करने की आवश्यकता होगी
df.loc[:, {condition}]
जहां {condition}
कुछ स्थिति का उपयोग करके बनाया गया है columns.get_level_values
।
उपयोग करने के लिए query
, आपका एकमात्र विकल्प अनुक्रमणिका, सूचकांक पर क्वेरी और फिर से प्रस्ताव करना है:
df3.T.query(...).T
अनुशंसित नहीं, अन्य 3 विकल्पों में से एक का उपयोग करें।
level
तर्क के बारे में पता नहीं थाIndex.isin
!