पंक्तियों को क्रमबद्ध करना — और टाई होने पर क्या करें
sort_values से पंक्तियों को क्रम में लगाना: एक या कई कॉलम, प्रत्येक की अपनी दिशा, मिसिंग वैल्यूज़ और संख्याओं जैसा दिखने वाला टेक्स्ट — साथ ही "टॉप N" के लिए nlargest, और कट-ऑफ पर टाई होना क्यों कोई संयोग नहीं बल्कि एक सुविचारित निर्णय होना चाहिए।
- 1समस्या
- 2समझें
- 3उदाहरण
- 4अनुमान
- 5स्वयं करें
- 6चुनौती
वह समस्या जिसे हम हल कर रहे हैं
दुकान के मालिक एक संक्षिप्त संदेश भेजते हैं: "इस महीने हमारे सबसे बड़े ऑर्डर्स कौन से थे? मुझे शीर्ष तीन भेजें।"
डेटा वही जाना-पहचाना orders.csv है — दुकान की तीन शाखाओं (north, south और east) से आठ ऑर्डर्स। आठ पंक्तियों के साथ आप केवल देखकर ही उत्तर दे सकते हैं। quantity कॉलम में नीचे देखें, पहले 30 खोजें, फिर 20, फिर 12। हो गया।
अब वास्तविक फ़ाइल की कल्पना करें: चार हज़ार ऑर्डर्स। तीन सबसे बड़ी संख्याएँ खोजने के लिए किसी कॉलम में नीचे की ओर देखना अब कोई समाधान नहीं है, यह महज़ एक उम्मीद है। और मालिक का अगला संदेश पहले ही रास्ते में है: "क्या आप मुझे शाखा के अनुसार समूहीकृत (grouped) सूची भेज सकते हैं, जिसमें प्रत्येक शाखा के भीतर सबसे बड़ा ऑर्डर पहले हो? और कृपया सबसे नए ऑर्डर्स सबसे ऊपर रखें।"
इनमें से प्रत्येक अनुरोध वास्तव में एक ही संक्रिया (operation) है: पंक्तियों को एक उपयोगी क्रम में लगाना, और फिर ऊपर से पढ़ना। यही सॉर्टिंग (sorting) है, और पांडास में यह एक अकेला मेथड है, sort_values()।
लेकिन मेथड तो सबसे आसान हिस्सा है। असली सवाल इसके इर्द-गिर्द होते हैं, और यहीं पर रिपोर्ट्स गलत हो जाती हैं:
- किसके आधार पर "सबसे बड़ा"? मात्रा (quantity), कीमत (price), या ऑर्डर से प्राप्त कुल आय? प्रत्येक आधार एक अलग शीर्ष तीन देता है।
- जब दो ऑर्डर्स के मान समान (टाई) हों, तो कौन सा पहले आता है — और क्या हर बार कोड चलाने पर यह उत्तर बदल जाता है?
- उस ऑर्डर का क्या होता है जिसकी मात्रा रिक्त (blank) है?
- यदि संख्याओं का एक कॉलम गलती से टेक्स्ट के रूप में पढ़ा गया था, तो बिना किसी चेतावनी के
"9"का क्रम"30"के बाद आता है।
यह अध्याय उस मेथड को सिखाता है और, इससे भी महत्वपूर्ण बात यह है कि उन निर्णयों को लेना सिखाता है।
इस अध्याय के अंत में आप कर पाएंगे
sort_values()के साथ एक या कई कॉलमों के आधार पर टेबल को सॉर्ट करना, प्रत्येक के लिए उसकी अपनी दिशा तय करना, और परिणाम को खोने के बजाय सहेजना- यह समझाना कि इंडेक्स लेबल्स अपनी पंक्तियों के साथ क्यों चलते हैं, और लेबल्स को बनाए रखने,
sort_index()औरreset_index(drop=True)के बीच सही चुनाव करना - जानबूझकर टाई को हल करना, और
na_positionसे यह तय करना कि मिसिंग वैल्यूज़ कहाँ जाएँ head(),nlargest()औरnsmallest()के साथ "शीर्ष N" प्रश्नों के उत्तर देना — जिसमें किसी सबसेट का शीर्ष N और कट-ऑफ पर टाई शामिल हैंkey=के साथ अक्षरों के केस (छोटे-बड़े अक्षर) की परवाह किए बिना टेक्स्ट सॉर्ट करना, और टेक्स्ट के रूप में संग्रहीत संख्याओं को उनके सॉर्ट होने के तरीके से पहचानना
ज़रूरी शर्तें: मिसिंग डेटा — रिक्त मानों को खोजना, हटाना और भरना।
पहले फ़ाइल बनाएं
इस अध्याय का प्रत्येक उदाहरण orders.csv फ़ाइल पढ़ता है, वही फ़ाइल जो अध्याय चार से उपयोग की जा रही है। यदि आपके प्रोजेक्ट फ़ोल्डर में यह अभी तक नहीं है, तो इसे ठीक इन पंक्तियों के साथ बनाएं:
order_id,date,branch,product,category,quantity,price
1001,2024-03-01,north,pen,stationery,12,15.0
1002,2024-03-01,south,notebook,stationery,5,60.0
1003,2024-03-02,north,bag,accessories,2,850.0
1004,2024-03-02,east,bottle,accessories,7,120.0
1005,2024-03-03,north,eraser,stationery,30,8.0
1006,2024-03-03,south,bag,accessories,1,850.0
1007,2024-03-04,east,pen,stationery,20,15.0
1008,2024-03-04,north,bottle,accessories,4,120.0आगे का एक अनुभाग दूसरी फ़ाइल, orders_gaps.csv का उपयोग करता है। यह वही टेबल है जिसमें दो ऑर्डर्स (1002 और 1007) की मात्रा रिक्त छोड़ दी गई है — उसी प्रकार की रिक्तता जिसे अध्याय छह में खोजना सिखाया गया था:
order_id,date,branch,product,category,quantity,price
1001,2024-03-01,north,pen,stationery,12,15.0
1002,2024-03-01,south,notebook,stationery,,60.0
1003,2024-03-02,north,bag,accessories,2,850.0
1004,2024-03-02,east,bottle,accessories,7,120.0
1005,2024-03-03,north,eraser,stationery,30,8.0
1006,2024-03-03,south,bag,accessories,1,850.0
1007,2024-03-04,east,pen,stationery,,15.0
1008,2024-03-04,north,bottle,accessories,4,120.0कोड लिखने से पहले क्या सोचें
सॉर्टिंग इतनी सरल लगती है कि योजना बनाने की आवश्यकता महसूस नहीं होती। लेकिन ऐसा नहीं है, क्योंकि सॉर्टिंग कभी विफल नहीं होती — यह हमेशा कोई न कोई क्रम उत्पन्न कर ही देती है। यदि आपने गलत चीज़ के आधार पर सॉर्ट किया है, तो परिणाम सही सॉर्ट की तरह ही सुव्यवस्थित दिखाई देता है। इसलिए विचार कोड लिखने से पहले होना चाहिए।
1. सवाल को एक वाक्य में लिखें, जिसमें कॉलम का नाम शामिल हो। "सबसे बड़े ऑर्डर्स" ऐसा सवाल नहीं है जिसका उत्तर पांडास सीधे दे सके। लेकिन "सबसे बड़ी quantity वाले तीन ऑर्डर्स" ऐसा सवाल है। इसी तरह "सबसे अधिक price वाले तीन ऑर्डर्स" भी। वे दोनों अलग-अलग उत्तर देते हैं — 850 वाला बैग सबसे महंगा आइटम है, लेकिन केवल दो बैग बेचे गए थे। तय करें कि मालिक का क्या तात्पर्य है। यदि आप नहीं जानते, तो पूछें; इसमें केवल एक संदेश लगता है, जबकि गलत शीर्ष तीन विश्वास खो देता है।
2. सॉर्ट करने से पहले इनपुट की जाँच करें। सॉर्ट के लिए तीन चीज़ें महत्वपूर्ण हैं: पंक्तियों की संख्या, वे डेटा प्रकार (dtypes) जिनके आधार पर आप सॉर्ट करेंगे, और क्या उन कॉलमों में कोई रिक्त मान हैं।
import pandas as pd
orders = pd.read_csv("orders.csv")
print(orders.shape)
print(orders.dtypes)
print(orders["quantity"].isna().sum())(8, 7)
order_id int64
date str
branch str
product str
category str
quantity int64
price float64
dtype: object
0आठ पंक्तियाँ, सात कॉलम। quantity का प्रकार int64 है और price का float64, इसलिए वे संख्याओं के रूप में सॉर्ट होंगे। branch और product का प्रकार str है — यानी टेक्स्ट, जो वर्णानुक्रम (alphabetically) में सॉर्ट होगा। date भी str है। यहाँ यह कोई समस्या नहीं है, और इसका कारण जानना उपयोगी है: YYYY-MM-DD के रूप में लिखी गई तिथियाँ टेक्स्ट के रूप में भी सही ढंग से सॉर्ट होती हैं, क्योंकि सबसे महत्वपूर्ण भाग (वर्ष) पहले आता है। 4/3/2024 के रूप में लिखी गई तिथियाँ सही सॉर्ट नहीं होतीं। और quantity में कोई रिक्त मान नहीं है, इसलिए हमें यह तय करने की आवश्यकता नहीं है कि मिसिंग वैल्यूज़ कहाँ जाएँगी — अभी के लिए।
3. अपेक्षित आउटपुट का एक स्केच बनाएं। "मात्रा के आधार पर शीर्ष तीन" के लिए उत्तर तीन पंक्तियाँ होना चाहिए, सबसे बड़ा पहले: 30 (इरेज़र, ऑर्डर 1005), फिर 20 (पेन, 1007), फिर 12 (पेन, 1001)। कुछ भी चलाने से पहले इसे लिख लेने से आपको कोड के परिणाम की जाँच करने के लिए एक आधार मिल जाता है।
4. सॉर्ट के लिए आवश्यक विवरण तय करें।
- Key (की) — कौन सा कॉलम, या कौन से कॉलम, क्रम तय करेंगे? यह
by=बन जाता है। - Direction (दिशा) — प्रत्येक की के लिए सबसे छोटा पहले या सबसे बड़ा पहले? यह
ascending=बन जाता है। - Ties (टाई) — यदि दो पंक्तियों का मान समान है, तो कौन पहले आएगा? यह दूसरा की बन जाता है, या
kind="stable"। - Blanks (रिक्त मान) — क्या मिसिंग वैल्यूज़ पहले आनी चाहिए या अंत में? यह
na_position=बन जाता है। - How many (कितनी पंक्तियाँ) — सभी पंक्तियाँ, या केवल शीर्ष N? यह
.head(n)याnlargest()बन जाता है। - Index (इंडेक्स) — क्या पुराने पंक्ति लेबल्स का बाद में कोई अर्थ है? उन्हें बनाए रखें, या
reset_index(drop=True)से हटा दें।
5. सही टूल चुनें।
- सभी पंक्तियाँ, एक या अधिक कॉलमों के क्रम में:
sort_values() - किसी संख्यात्मक कॉलम के आधार पर केवल शीर्ष या न्यूनतम N:
nlargest()/nsmallest() - पंक्तियों को वापस मूल इंडेक्स क्रम में लाना:
sort_index() - किसी सबसेट के भीतर शीर्ष N ("north शाखा में"): पहले फ़िल्टर करें, फिर सॉर्ट करें, फिर
head()
6. जानें कि आप इसकी जाँच कैसे करेंगे। सॉर्ट के बाद, पहली पंक्तियों को आपके स्केच से मेल खाना चाहिए, shape अपरिवर्तित होना चाहिए (सॉर्ट कभी भी पंक्तियाँ जोड़ता या हटाता नहीं है), और एक संख्यात्मक की के लिए कॉलम का मान पृष्ठ पर ऊपर से नीचे तक एक ही दिशा में बढ़ना या घटना चाहिए।
sort_values() — एक कॉलम
प्रिंटआउट को संक्षिप्त रखने के लिए, उदाहरण सात में से पाँच कॉलम दिखाते हैं। cols केवल कॉलम नामों की एक सूची है, जिसका उपयोग अध्याय चार के डबल-ब्रैकेट चयन के साथ किया गया है।
cols = ["order_id", "branch", "product", "quantity", "price"]
by_qty = orders.sort_values("quantity")
print(by_qty[cols])order_id branch product quantity price
5 1006 south bag 1 850.0
2 1003 north bag 2 850.0
7 1008 north bottle 4 120.0
1 1002 south notebook 5 60.0
3 1004 east bottle 7 120.0
0 1001 north pen 12 15.0
6 1007 east pen 20 15.0
4 1005 north eraser 30 8.0डिफ़ॉल्ट दिशा ascending (आरोही) है — सबसे छोटा पहले। quantity कॉलम को ऊपर से नीचे पढ़ें: 1, 2, 4, 5, 7, 12, 20, 30। यही योजना से की गई जाँच है: एक संख्यात्मक की केवल ऊपर की ओर बढ़नी चाहिए।
अब बाएँ किनारे को देखें। इंडेक्स अब 0, 1, 2, … नहीं है। यह 5, 2, 7, 1, 3, 0, 6, 4 दिखा रहा है।
इंडेक्स पंक्तियों के साथ क्यों चलता है
पांडास ने पंक्तियों को पुनः क्रमांकित (renumber) नहीं किया, और यह जानबूझकर किया गया है। एक इंडेक्स लेबल पंक्ति का नाम होता है, उसकी स्थिति नहीं। लेबल 5 सॉर्ट से पहले ऑर्डर 1006 था और सॉर्ट के बाद भी यह ऑर्डर 1006 ही है। यदि सॉर्ट करने से पंक्तियाँ पुनः क्रमांकित हो जातीं, तो प्रत्येक लेबल अचानक एक अलग ऑर्डर की ओर इशारा करने लगता, और "पंक्ति 5" के बारे में आपने जो कुछ भी नोट किया था वह चुपचाप गलत हो जाता।
इसलिए सॉर्ट के बाद "पहली पंक्ति" कहने के दो अलग-अलग तरीके होते हैं, और वे अब एक-दूसरे से सहमत नहीं होते:
print(by_qty.iloc[0]["order_id"])
print(by_qty.loc[0]["order_id"])1006
1001iloc[0] का अर्थ है स्थिति (position) शून्य — पृष्ठ की सबसे पहली पंक्ति, यानी ऑर्डर 1006। और loc[0] का अर्थ है लेबल 0 वाली पंक्ति — यानी ऑर्डर 1001, जो अब पृष्ठ पर छठे स्थान पर है। अध्याय चार में यह अंतर समझाया गया था; सॉर्टिंग वह संक्रिया है जो इसे महत्वपूर्ण बनाती है। जब आप सॉर्ट करने के बाद "शीर्ष पंक्ति" चाहते हैं, तो iloc या head() का उपयोग करें, क्योंकि दोनों ही स्थितियों की गिनती करते हैं।
सबसे बड़ा पहले: ascending=False
print(orders.sort_values("quantity", ascending=False)[cols])order_id branch product quantity price
4 1005 north eraser 30 8.0
6 1007 east pen 20 15.0
0 1001 north pen 12 15.0
3 1004 east bottle 7 120.0
1 1002 south notebook 5 60.0
7 1008 north bottle 4 120.0
2 1003 north bag 2 850.0
5 1006 south bag 1 850.0शीर्ष तीन 1005, 1007 और 1001 हैं — बिल्कुल हमारी योजना के स्केच के अनुसार। केवल उन तीनों को भेजने के लिए, head(3) जोड़ें:
top3 = orders.sort_values("quantity", ascending=False).head(3)
print(top3[cols])order_id branch product quantity price
4 1005 north eraser 30 8.0
6 1007 east pen 20 15.0
0 1001 north pen 12 15.0श्रृंखला को बाएँ से दाएँ पढ़ने पर योजना स्पष्ट दिखती है: orders लें, सबसे बड़ी मात्रा पहले रखें, पहले तीन रखें। यह "सॉर्ट करें, फिर head" पैटर्न अधिकांश "शीर्ष N" सवालों का जवाब देता है।
टेक्स्ट वर्णानुक्रम में सॉर्ट होता है
एक str कॉलम डिक्शनरी क्रम में सॉर्ट होता है:
print(orders.sort_values("product")[cols])order_id branch product quantity price
2 1003 north bag 2 850.0
5 1006 south bag 1 850.0
3 1004 east bottle 7 120.0
7 1008 north bottle 4 120.0
4 1005 north eraser 30 8.0
1 1002 south notebook 5 60.0
0 1001 north pen 12 15.0
6 1007 east pen 20 15.0bag, bottle से पहले आता है क्योंकि a, o से पहले आता है। दो बैग, दो बोतलें और दो पेन — ये टाई (ties) हैं, और हम इस सवाल पर जल्द ही वापस आएँगे कि टाई होने पर कौन सा पहले आता है।
सॉर्ट एक नई टेबल लौटाता है
यह वह गलती है जो लगभग हर कोई एक बार ज़रूर करता है, और इससे कोई एरर नहीं आता:
orders.sort_values("quantity", ascending=False)
print(orders[cols].head(3))order_id branch product quantity price
0 1001 north pen 12 15.0
1 1002 south notebook 5 60.0
2 1003 north bag 2 850.0कुछ भी सॉर्ट नहीं हुआ। sort_values() मूल orders को नहीं बदलता; यह नए क्रम में एक नया DataFrame बनाता है और उसे लौटाता है। पहली लाइन ने वह सॉर्ट की गई टेबल बनाई और, क्योंकि किसी ने उसे किसी वेरिएबल में नहीं सहेजा, इसलिए उसे छोड़ दिया। orders बिल्कुल वैसा ही है जैसा read_csv ने बनाया था।
पांडास इस तरह क्यों काम करता है? क्योंकि मूल क्रम भी एक जानकारी है। orders.csv में यह वह क्रम है जिस क्रम में ऑर्डर्स प्राप्त हुए थे। यदि प्रत्येक सॉर्ट आपकी एकमात्र प्रति को पुनर्व्यवस्थित कर देता, तो आप कभी भी "फ़ाइल जैसी थी" उस स्थिति में वापस नहीं आ पाते, और एक रिपोर्ट के लिए लिखा गया सॉर्ट अगली रिपोर्ट के इनपुट को चुपचाप बदल देता। एक नया ऑब्जेक्ट लौटाने का अर्थ है कि सॉर्टिंग को आज़माना हमेशा सुरक्षित रहता है।
sort_values() कभी भी उस टेबल को नहीं बदलता जिस पर इसे कॉल किया जाता है। यदि आप परिणाम को किसी वेरिएबल में असाइन नहीं करते हैं, तो सॉर्ट हुआ और छोड़ दिया गया — और कोई चेतावनी आपको सतर्क नहीं करती।इसलिए परिणाम को सहेजें, या तो किसी नए नाम में या उसी नाम में:
by_qty_desc = orders.sort_values("quantity", ascending=False) # keep both
print(by_qty_desc["order_id"].head(3).tolist())
print(orders["order_id"].head(3).tolist())[1005, 1007, 1001]
[1001, 1002, 1003]सॉर्ट की गई कॉपी में बड़े ऑर्डर्स सबसे ऊपर हैं; मूल टेबल अछूती है। orders = orders.sort_values(...) लिखना भी पूरी तरह से ठीक है जब आप सुनिश्चित हों कि आपको पुराने क्रम की आवश्यकता नहीं है।
आप पुराने कोड में inplace=True देख सकते हैं। यह टेबल को उसी जगह बदलता है और None लौटाता है, जिससे अपना एक अलग बग पैदा होता है (देखें जब कोड काम न करे)। पांडास 3 में Copy-on-Write के साथ, inplace=True कोई मेमोरी भी नहीं बचाता है। परिणाम को असाइन करना अधिक स्पष्ट है: आप लाइन पर ही देख सकते हैं कि सॉर्ट की गई टेबल कहाँ जा रही है।
एकाधिक कॉलम: प्राथमिकता और दिशा
मालिक का दूसरा अनुरोध था: "शाखा के अनुसार समूहीकृत, प्रत्येक शाखा के भीतर सबसे बड़ा पहले।" ये दो की हैं, और सूची का क्रम प्राथमिकता (priority) का क्रम है:
by_branch = orders.sort_values(["branch", "quantity"], ascending=[True, False])
print(by_branch[cols])order_id branch product quantity price
6 1007 east pen 20 15.0
3 1004 east bottle 7 120.0
4 1005 north eraser 30 8.0
0 1001 north pen 12 15.0
7 1008 north bottle 4 120.0
2 1003 north bag 2 850.0
1 1002 south notebook 5 60.0
5 1006 south bag 1 850.0इसे वैसे पढ़ें जैसे पांडास ने इसे बनाया है। सबसे पहले, प्रत्येक पंक्ति को branch द्वारा रखा जाता है, A से Z: east, north, south। दूसरा की, quantity, केवल तभी देखा जाता है जब पहला की टाई होता है — east के भीतर, north के भीतर, south के भीतर। north के भीतर यह 30, 12, 4, 2 चलता है: सबसे बड़ा पहले, क्योंकि ascending की दूसरी प्रविष्टि False है।
ascending प्रत्येक की के लिए एक True/False लेता है, उसी क्रम में जिस क्रम में by है। एक अकेला False दोनों कीज़ पर लागू होगा और south को पहले रख देगा।
सूची में कॉलमों की अदला-बदली करने से सवाल पूरी तरह बदल जाता है:
print(orders.sort_values(["quantity", "branch"], ascending=[False, True])[cols].head(4))order_id branch product quantity price
4 1005 north eraser 30 8.0
6 1007 east pen 20 15.0
0 1001 north pen 12 15.0
3 1004 east bottle 7 120.0अब मात्रा का शासन है, और branch केवल तभी मायने रखती जब दो ऑर्डर्स की मात्रा समान होती — जो कि किसी की नहीं है। शाखाएँ बिखर गई हैं। इसलिए सूची लिखने से पहले पूछा जाने वाला सवाल यह है: "रिपोर्ट किस आधार पर व्यवस्थित है?" वह कॉलम पहले आता है।
टाई: क्रम को एक निर्णय बनाएं, कोई संयोग नहीं
price के अनुसार सॉर्ट करें, सबसे महंगी वस्तु पहले:
print(orders.sort_values("price", ascending=False)[cols])order_id branch product quantity price
2 1003 north bag 2 850.0
5 1006 south bag 1 850.0
7 1008 north bottle 4 120.0
3 1004 east bottle 7 120.0
1 1002 south notebook 5 60.0
0 1001 north pen 12 15.0
6 1007 east pen 20 15.0
4 1005 north eraser 30 8.0120 वाली दो बोतलों को देखें। फ़ाइल में, ऑर्डर 1004, 1008 से पहले आता है। सॉर्ट की गई टेबल में, 1008 पहले आता है। कुछ भी टूटा नहीं है: एक अकेले की के लिए, पांडास का डिफ़ॉल्ट सॉर्टिंग एल्गोरिदम (quicksort) टाई पंक्तियों को उनके मूल क्रम में रखने का वादा नहीं करता है, और यहाँ उसने ऐसा नहीं किया। 850 वाले दो बैग फ़ाइल क्रम में रहे, दो बोतलों ने स्थान बदल लिया — ऐसा कोई नियम नहीं है जिसका आप पहले से अनुमान लगा सकते थे।
आमतौर पर इससे कोई फ़र्क नहीं पड़ता। यह उस क्षण मायने रखने लगता है जब आप सूची को काटते हैं। यदि रिपोर्ट "तीन सबसे महंगे ऑर्डर्स" है, तो तीसरा स्थान 1004 और 1008 के बीच एक टाई है, और उनमें से कौन सूची में जगह बनाता है यह एल्गोरिदम द्वारा तय किया गया था, आपके द्वारा नहीं। थोड़ी अलग फ़ाइल पर वही कोड चलाएं और उत्तर बदल सकता है।
उस निर्णय को वापस अपने हाथ में लेने के दो तरीके हैं।
विकल्प 1: एक स्थिर सॉर्ट (stable sort)। kind="stable" वादा करता है कि टाई पंक्तियाँ सॉर्ट से पहले का अपना क्रम बनाए रखती हैं — यहाँ, फ़ाइल का क्रम:
stable = orders.sort_values("price", ascending=False, kind="stable")
print(stable["order_id"].tolist())[1003, 1006, 1004, 1008, 1002, 1001, 1007, 1005]विकल्प 2 (आमतौर पर बेहतर): एक स्पष्ट टाई-ब्रेकर। तय करें कि टाई होने पर किसे जीतना चाहिए। बिक्री रिपोर्ट के लिए, "यदि कीमत समान है, तो बड़ा ऑर्डर पहले" एक समझदारी भरा नियम है:
tie_broken = orders.sort_values(["price", "quantity"], ascending=[False, False])
print(tie_broken[cols])order_id branch product quantity price
2 1003 north bag 2 850.0
5 1006 south bag 1 850.0
3 1004 east bottle 7 120.0
7 1008 north bottle 4 120.0
1 1002 south notebook 5 60.0
6 1007 east pen 20 15.0
0 1001 north pen 12 15.0
4 1005 north eraser 30 8.0बोतलों को फिर से देखें: 1004 अब 1008 से ऊपर है, क्योंकि 7, 4 से बड़ा है। और 15 वाले दो पेन: पहले, 1001 पहले आया था; अब 1007 जीतता है, क्योंकि 20, 12 से बड़ा है — और यह हर मशीन पर, किसी भी क्रम में फ़ाइल आने पर, हर बार जीतेगा। एक टाई-ब्रेकर एक संयोग को ऐसे नियम में बदल देता है जिसे आप मालिक को समझा सकते हैं। (जब आप एक से अधिक कॉलम द्वारा सॉर्ट करते हैं, तो पांडास का सॉर्ट वैसे भी स्थिर होता है, इसलिए कीज़ की एक सूची वास्तविक टाई को कभी नहीं बिखेरती।)
यदि आपके पास कोई व्यावसायिक नियम नहीं है, तो order_id एक अच्छा अंतिम की बनता है: यह अद्वितीय (unique) है, इसलिए इसके बाद कोई टाई नहीं बचता।
मिसिंग वैल्यूज़: na_position
दो रिक्त मात्राओं वाली फ़ाइल का संस्करण पढ़ें:
gaps = pd.read_csv("orders_gaps.csv")
print(gaps["quantity"].isna().sum())
print(gaps.sort_values("quantity", ascending=False)[cols])2
order_id branch product quantity price
4 1005 north eraser 30.0 8.0
0 1001 north pen 12.0 15.0
3 1004 east bottle 7.0 120.0
7 1008 north bottle 4.0 120.0
2 1003 north bag 2.0 850.0
5 1006 south bag 1.0 850.0
1 1002 south notebook NaN 60.0
6 1007 east pen NaN 15.0ध्यान देने योग्य दो बातें। पहला, quantity अब 30.0, 12.0 के रूप में प्रिंट होता है — रिक्त मानों ने कॉलम को float64 में बदल दिया, जैसा कि अध्याय छह में बताया गया था, क्योंकि NaN एक फ़्लोट है। दूसरा, सबसे बड़े मान पहले मांगने के बावजूद NaN पंक्तियाँ सबसे नीचे चली गईं। यह डिफ़ॉल्ट व्यवहार है, na_position="last", और यह दोनों दिशाओं में लागू होता है: एक अनुपस्थित मान "छोटा" या "बड़ा" नहीं होता, यह अज्ञात होता है, इसलिए पांडास अनुमान लगाने के बजाय इसे एक तरफ़ रख देता है।
ध्यान दें कि इसने शीर्ष तीन के साथ क्या किया। ऑर्डर 1007 ने वास्तव में 20 पेन बेचे थे, लेकिन इस फ़ाइल में इसकी मात्रा रिक्त है, इसलिए यह शीर्ष तीन से बाहर हो गया और 1004 ने इसकी जगह ले ली। एक सॉर्ट मिसिंग डेटा को ठीक नहीं कर सकता; यह केवल आपको दिखा सकता है कि रिक्तियाँ कहाँ गईं। यही कारण है कि योजना का चरण 2 सॉर्ट करने से पहले रिक्तियों की गणना करता है।
जब आप डेटा की जाँच (audit) कर रहे होते हैं, तो आप अक्सर इसका उल्टा चाहते हैं — समस्याएँ सबसे ऊपर हों, जहाँ आप उन्हें देख सकें:
print(gaps.sort_values("quantity", na_position="first")[cols].head(3))order_id branch product quantity price
1 1002 south notebook NaN 60.0
6 1007 east pen NaN 15.0
5 1006 south bag 1.0 850.0इसलिए na_position कोई फ़ॉर्मेटिंग विकल्प नहीं है। "last" रिपोर्ट के लिए उपयुक्त है, जहाँ रिक्तियाँ वास्तविक मानों को बाहर न करें। "first" ऑडिट के लिए उपयुक्त है, जहाँ रिक्तियाँ वही हैं जिन्हें आप खोज रहे हैं।
शुरुआत में वापस: sort_index() और reset_index()
क्योंकि प्रत्येक पंक्ति ने अपना लेबल बनाए रखा, इसलिए मूल क्रम कभी खोता नहीं है। इंडेक्स के अनुसार सॉर्ट करने पर यह वापस आ जाता है:
restored = by_qty.sort_index()
print(restored["order_id"].tolist())[1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008]sort_index() भी ascending=False स्वीकार करता है, जिसके द्वारा आप टेबल को "नवीनतम लेबल पहले" सूचीबद्ध कर सकते हैं।
कभी-कभी पुराने लेबल्स का कोई अर्थ नहीं रह जाता। यदि आप एक रैंकिंग सूची बनाने और उसे भेजने के लिए सॉर्ट करते हैं, तो साइड में 4, 6, 0 लेबल्स भ्रमित करने वाले होते हैं। reset_index(drop=True) उन्हें हटा देता है और पंक्तियों को उनके नए क्रम में 0, 1, 2, … से क्रमांकित करता है:
ranked = orders.sort_values("quantity", ascending=False).reset_index(drop=True)
print(ranked[cols].head(3))
print(ranked.loc[0, "order_id"])order_id branch product quantity price
0 1005 north eraser 30 8.0
1 1007 east pen 20 15.0
2 1001 north pen 12 15.0
1005अब loc[0] और iloc[0] फिर से सहमत हैं: दोनों ऑर्डर 1005 हैं, जो सबसे बड़ा है। drop=True के बिना, पांडास पुराने लेबल्स को index नामक एक नए कॉलम के रूप में रखता — यदि आप पंक्तियों को मूल स्रोत से मिलाना चाहते हैं तो उपयोगी है, अन्यथा यह अव्यवस्था है।
किसे चुनें? जब आप अभी भी डेटा के साथ काम कर रहे हों और पंक्तियों को मूल से मिलाने की आवश्यकता हो, तो लेबल्स रखें। जब क्रम ही अंतिम परिणाम हो — जैसे रैंकिंग या शीर्ष दस की सूची — तो उन्हें रीसेट करें।
"शीर्ष N" का संक्षिप्त तरीका: nlargest() और nsmallest()
"मात्रा के अनुसार शीर्ष तीन" इतना सामान्य है कि पांडास के पास एक ऐसा मेथड है जो ठीक यही कहता है:
print(orders.nlargest(3, "quantity")[cols])order_id branch product quantity price
4 1005 north eraser 30 8.0
6 1007 east pen 20 15.0
0 1001 north pen 12 15.0यह बिल्कुल sort_values("quantity", ascending=False).head(3) जैसी ही पंक्तियाँ देता है। इसे प्राथमिकता क्यों दें? यह लाइन तंत्र (mechanism) के बजाय उद्देश्य बताती है — "तीन सबसे बड़े"। और एक बड़ी टेबल पर यह तेज़ होता है, क्योंकि इसे केवल तीन रखने के लिए सभी पंक्तियों को क्रम में लगाने की आवश्यकता नहीं होती।
nsmallest() इसका ठीक उल्टा है: दुकान में सबसे सस्ते तीन आइटम:
print(orders.nsmallest(3, "price")[cols])order_id branch product quantity price
4 1005 north eraser 30 8.0
0 1001 north pen 12 15.0
6 1007 east pen 20 15.0कट-ऑफ पर टाई: keep=
तीन सबसे महंगे आइटम मांगें और एक असहज स्थिति उत्पन्न होती है:
print(orders.nlargest(3, "price")[cols])order_id branch product quantity price
2 1003 north bag 2 850.0
5 1006 south bag 1 850.0
3 1004 east bottle 7 120.0तीसरा स्थान 120 है — लेकिन दो ऑर्डर्स की कीमत 120 है, 1004 और 1008। पांडास ने उनमें से एक लौटाया — डिफ़ॉल्ट keep="first" के साथ, जो टेबल में पहले दिखाई देता है — और चुपचाप दूसरे को छोड़ दिया। यदि आप "शीर्ष तीन" को पुरस्कार दे रहे हैं, तो यह 1008 के साथ अनुचित है। keep="all" कट-ऑफ पर टाई होने वाली प्रत्येक पंक्ति को रखता है, भले ही इसका मतलब N से अधिक पंक्तियाँ हों:
print(orders.nlargest(3, "price", keep="all")[cols])order_id branch product quantity price
2 1003 north bag 2 850.0
5 1006 south bag 1 850.0
3 1004 east bottle 7 120.0
7 1008 north bottle 4 120.0"शीर्ष तीन" के लिए चार पंक्तियाँ। यह कोई बग नहीं है: जब तीसरा स्थान साझा किया जाता है तो यह सच्चा उत्तर है। क्या आप इसे चाहते हैं, यह फिर से एक योजना का निर्णय है।
nlargest और nsmallest केवल संख्यात्मक कॉलमों पर काम करते हैं। टेक्स्ट के लिए, sort_values और head का उपयोग करें।
किसी सबसेट का शीर्ष N: पहले फ़िल्टर करें, फिर सॉर्ट करें, फिर काटें
"north शाखा में दो सबसे बड़े ऑर्डर्स कौन से थे?" यह अध्याय पाँच को इस अध्याय के साथ जोड़ता है, और चरणों का क्रम महत्वपूर्ण है:
north = orders[orders["branch"] == "north"]
top_north = north.sort_values("quantity", ascending=False).head(2)
print(top_north[cols])order_id branch product quantity price
4 1005 north eraser 30 8.0
0 1001 north pen 12 15.0पहले फ़िल्टर करें, क्योंकि सवाल केवल north शाखा के बारे में है। यदि आपने पूरी टेबल को सॉर्ट किया और पहले head(2) लिया, तो आपको 1005 और 1007 मिलते — और 1007 east शाखा का है। बाद में फ़िल्टर करने पर केवल एक पंक्ति बचती, और आप एक प्रविष्टि के साथ "शीर्ष दो" की रिपोर्ट करते। नियम: उन पंक्तियों तक सीमित करें जिनके बारे में सवाल है, फिर उन्हें रैंक करें, फिर काटें।
यही काम nlargest की श्रृंखला के साथ भी होता है: orders[orders["branch"] == "north"].nlargest(2, "quantity")।
केस की परवाह किए बिना टेक्स्ट सॉर्ट करना: key=
टेक्स्ट सॉर्टिंग वर्णों की तुलना उनके कोड के अनुसार करती है, और प्रत्येक बड़ा अक्षर प्रत्येक छोटे अक्षर से पहले आता है। मनुष्यों द्वारा टाइप किए गए डेटा में दोनों का मिश्रण होता है:
names = pd.DataFrame({"product": ["pen", "Notebook", "bag", "Bottle", "eraser"]})
print(names.sort_values("product"))product
3 Bottle
1 Notebook
2 bag
4 eraser
0 penBottle और Notebook केवल इसलिए bag से आगे निकल गए क्योंकि वे बड़े अक्षर से शुरू होते हैं। कोई भी पाठक इसे वर्णानुक्रम नहीं कहेगा।
आप डेटा को ठीक कर सकते थे, लेकिन अक्सर आपको ऐसा नहीं करना चाहिए — वर्तनी वही हो सकती है जो ग्राहक ने लिखी थी। key= तर्क आपको मूल मानों को बनाए रखते हुए कॉलम के रूपांतरित (transformed) संस्करण के आधार पर सॉर्ट करने की अनुमति देता है। यह एक ऐसा फ़ंक्शन लेता है जो पूरे कॉलम को प्राप्त करता है और सॉर्ट करने के लिए रूपांतरित संस्करण लौटाता है:
print(names.sort_values("product", key=lambda col: col.str.lower()))product
2 bag
3 Bottle
4 eraser
1 Notebook
0 penलोअरकेस कॉपी का उपयोग केवल तुलना के लिए किया जाता है और फिर उसे छोड़ दिया जाता है। टेबल अभी भी Bottle और Notebook को ठीक वैसे ही दिखाती है जैसे वे टाइप किए गए थे। (lambda col: col.str.lower() एक पंक्ति का फ़ंक्शन है: कॉलम col दिए जाने पर, इसे लोअरकेस में लौटाएं।)
जब संख्याएँ टेक्स्ट के रूप में संग्रहीत हों
यहाँ वह जाल है जिसे पकड़ने के लिए dtypes वाला योजना चरण मौजूद है। मान लीजिए कि quantity टेक्स्ट के रूप में आया — फ़ाइल में कोई भटका हुआ "N/A", या कोई ऐसा सिस्टम जो सब कुछ स्ट्रिंग्स के रूप में निर्यात करता है। यह देखने के लिए कि यह क्या करता है, हम astype के साथ जानबूझकर ऐसा कॉलम बनाते हैं:
as_text = orders.astype({"quantity": "str"})
print(as_text["quantity"].dtype)
print(as_text.sort_values("quantity")[["order_id", "quantity"]])str
order_id quantity
5 1006 1
0 1001 12
2 1003 2
6 1007 20
4 1005 30
7 1008 4
1 1002 5
3 1004 71, 12, 2, 20, 30, 4, 5, 7। कोई एरर नहीं, और एक ऐसा क्रम जो लगभग सही दिखता है। टेक्स्ट की तुलना अक्षर-दर-अक्षर की जाती है: "12" शुरू होता है 1 से, जो 2 से छोटा है, इसलिए "12", "2" से पहले आता है — जैसे डिक्शनरी में "ab", "b" से पहले आता है। सॉर्ट ने बिल्कुल वही किया जो उसे बताया गया था। लेकिन उसे गलत चीज़ बताई गई थी।
दो सुराग इसे उजागर करते हैं: प्रिंटआउट में quantity बाईं ओर संरेखित (left-aligned) है, जिस तरह पांडास टेक्स्ट प्रिंट करता है, और dtype, str कहता है। असली समाधान कॉलम को संख्याओं में बदलना है (अध्याय छह का pd.to_numeric)। यदि आपको कॉलम को वैसा ही छोड़ना है, तो key= इसके बजाय संख्यात्मक मान द्वारा सॉर्ट कर सकता है:
fixed = as_text.sort_values("quantity", key=pd.to_numeric)
print(fixed["quantity"].tolist())['1', '2', '4', '5', '7', '12', '20', '30']अब सही क्रम है — लेकिन मान अभी भी स्ट्रिंग्स हैं, इसलिए आप उन्हें जोड़ नहीं सकते। फ़ाइल पढ़ने के तुरंत बाद कॉलम को एक बार बदल लेना सबसे अच्छा तरीका है। तब उसके बाद आने वाला हर सॉर्ट, फ़िल्टर और जोड़ बिना याद रखे सही काम करता है।
एक संपूर्ण उदाहरण
मालिक का पूरा अनुरोध, एक प्रोग्राम में उत्तर दिया गया: (1) अर्जित राजस्व द्वारा शीर्ष तीन ऑर्डर्स, (2) सबसे नए ऑर्डर्स पहले, (3) शाखा द्वारा एक सूची जिसमें प्रत्येक शाखा में सबसे बड़ा ऑर्डर पहले हो।
"अर्जित राजस्व" मात्रा गुणा कीमत है। कॉलम जोड़ना पाठ्यक्रम में बाद में अच्छी तरह से कवर किया गया है; अभी के लिए एक पंक्ति पर्याप्त है — एक नए कॉलम नाम को असाइन करने से वह बन जाता है।
sorted_report.py:
import pandas as pd
orders = pd.read_csv("orders.csv")
# Check the input before ranking anything
print("Rows, columns:", orders.shape)
print("Blank quantities:", orders["quantity"].isna().sum())
print()
orders["revenue"] = orders["quantity"] * orders["price"]
cols = ["order_id", "date", "branch", "product", "revenue"]
# 1. Top three by revenue, ties broken by the larger quantity, renumbered as a ranking
top3 = (
orders.sort_values(["revenue", "quantity"], ascending=[False, False])
.head(3)
.reset_index(drop=True)
)
print("Top three orders by revenue")
print(top3[cols])
print()
# 2. Newest first; within the same day, the bigger order first
newest = orders.sort_values(["date", "revenue"], ascending=[False, False])
print("Newest first")
print(newest[cols].head(4))
print()
# 3. By branch A-Z, biggest order first inside each branch
by_branch = orders.sort_values(["branch", "revenue"], ascending=[True, False])
print("By branch")
print(by_branch[cols])
print()
print("Still eight rows:", by_branch.shape[0] == orders.shape[0])Rows, columns: (8, 7)
Blank quantities: 0
Top three orders by revenue
order_id date branch product revenue
0 1003 2024-03-02 north bag 1700.0
1 1006 2024-03-03 south bag 850.0
2 1004 2024-03-02 east bottle 840.0
Newest first
order_id date branch product revenue
7 1008 2024-03-04 north bottle 480.0
6 1007 2024-03-04 east pen 300.0
5 1006 2024-03-03 south bag 850.0
4 1005 2024-03-03 north eraser 240.0
By branch
order_id date branch product revenue
3 1004 2024-03-02 east bottle 840.0
6 1007 2024-03-04 east pen 300.0
2 1003 2024-03-02 north bag 1700.0
7 1008 2024-03-04 north bottle 480.0
4 1005 2024-03-03 north eraser 240.0
0 1001 2024-03-01 north pen 180.0
5 1006 2024-03-03 south bag 850.0
1 1002 2024-03-01 south notebook 300.0
Still eight rows: Trueइसे इस तरह क्यों लिखा गया है:
- जाँच पहले आती है। किसी भी रैंकिंग से पहले
shapeऔर रिक्तियों की संख्या प्रिंट की जाती है। आधी पढ़ी गई फ़ाइल से या रिक्तियों को नीचे धकेल कर तैयार किए गए शीर्ष तीन भी उतने ही आश्वस्त दिखते। - "सबसे बड़े" को एक कॉलम में बदला गया।
quantityद्वारा रैंकिंग करने पर 30 इरेज़र सबसे ऊपर आते — 240 का व्यवसाय।revenueद्वारा रैंकिंग करने पर 1,700 मूल्य के दो बैग सबसे ऊपर आते हैं। योजना का पहला कदम — कॉलम के साथ सवाल लिखें — तय करता है कि मालिक को कौन सा उत्तर मिले। - प्रत्येक सॉर्ट में एक टाई-ब्रेकर है। 2024-03-04 को दो ऑर्डर्स हैं;
revenueतय करता है कि कौन सा पहले सूचीबद्ध हो, इसलिए हर रन पर रिपोर्ट समान रहती है। - केवल रैंकिंग को पुनः क्रमांकित किया गया है।
top3एक पूर्ण सूची है, इसलिए इसके लेबल्स 0, 1, 2 बन जाते हैं।newestऔरby_branchअपने मूल लेबल्स बनाए रखते हैं, ताकि किसी भी पंक्ति को वापस फ़ाइल से मिलाया जा सके। ordersको स्वयं कभी भी दोबारा सॉर्ट नहीं किया गया। प्रत्येक रिपोर्ट उसी अछूते इनपुट से बनी एक नई टेबल है, इसलिए तीनों उत्तर एक-दूसरे में हस्तक्षेप नहीं कर सकते।- अंतिम पंक्ति एक आसान जांच (assertion) है। एक सॉर्ट को कभी भी पंक्तियों की संख्या नहीं बदलनी चाहिए।
Trueप्रिंट करने में कुछ खर्च नहीं होता और यह, उदाहरण के लिए, गलत जगह छूटे हुए आकस्मिकhead()को पकड़ सकता है।
जब कोड काम न करे (सामान्य त्रुटियाँ)
KeyError: 'Quantity'
orders.sort_values("Quantity")KeyError: 'Quantity'by= में नाम कॉलम से बिल्कुल मेल खाना चाहिए — केस, स्पेस और सब कुछ। कॉलम quantity है, छोटे अक्षरों में। उद्धरण और किसी भी अतिरिक्त स्पेस सहित वास्तविक नाम देखने के लिए list(orders.columns) प्रिंट करें, जैसा कि अध्याय तीन में अनुशंसित किया गया था।
AttributeError: 'NoneType' object has no attribute 'head'
top = orders.sort_values("quantity", inplace=True)
top.head()AttributeError: 'NoneType' object has no attribute 'head'inplace=True के साथ, sort_values, orders को बदलता है और None लौटाता है। इसलिए top, None है, और None में कोई head() नहीं होता है। एक शैली चुनें: या तो अपनी पंक्ति पर orders.sort_values("quantity", inplace=True), या — बेहतर — inplace के बिना top = orders.sort_values("quantity")।
ValueError: Length of ascending (1) != length of by (2)
orders.sort_values(["branch", "quantity"], ascending=[False])ValueError: Length of ascending (1) != length of by (2)ascending की सूची में प्रति की एक प्रविष्टि की आवश्यकता होती है। दो की, दो बूलियन: ascending=[True, False]। (एक अकेला सादा False, जो सूची में नहीं है, मान्य है — यह प्रत्येक की पर लागू होता है।)
ValueError: For argument "ascending" expected type bool, received type str.
orders.sort_values("branch", ascending="False")ValueError: For argument "ascending" expected type bool, received type str.उद्धरण चिह्नों में "False" एक स्ट्रिंग है, बूलियन False नहीं। उद्धरण चिह्न हटा दें।
TypeError: Column 'branch' has dtype str, cannot use method 'nlargest' with this dtype
orders.nlargest(3, "branch")TypeError: Column 'branch' has dtype str, cannot use method 'nlargest' with this dtypenlargest और nsmallest केवल संख्याओं को रैंक करते हैं। "वर्णानुक्रम में अंतिम तीन शाखाएँ" के लिए orders.sort_values("branch", ascending=False).head(3) का उपयोग करें। यदि आपको किसी ऐसे कॉलम पर यह त्रुटि मिली जिसे आपने संख्यात्मक माना था, तो वास्तविक समस्या यह है कि इसे टेक्स्ट के रूप में पढ़ा गया था — dtypes की जाँच करें।
TypeError: '<' not supported between instances of 'str' and 'int'
mixed = pd.Series([12, "unknown", 5])
mixed.sort_values()TypeError: '<' not supported between instances of 'str' and 'int'यह कॉलम वास्तविक संख्याओं और टेक्स्ट के एक टुकड़े को रखता है, इसलिए इसका dtype, object है, और पायथन यह तय नहीं कर सकता कि "unknown" 12 से बड़ा है या छोटा। पहले कॉलम को साफ़ करें: pd.to_numeric(mixed, errors="coerce"), "unknown" को NaN में बदल देता है, और फिर सॉर्ट काम करता है और na_position तय करता है कि रिक्त स्थान कहाँ जाएगा।
चरण 4 / 6 — अनुमान
अपनी समझ की जाँच करें
दो बैग्स की कीमत सबसे ज़्यादा (850.0) है। क्या प्रिंट होगा?
from io import StringIO
import pandas as pd
# Stands in for orders.csv, so this snippet runs on its own.
RAW = """order_id,date,branch,product,category,quantity,price
1001,2024-03-01,north,pen,stationery,12,15.0
1002,2024-03-01,south,notebook,stationery,5,60.0
1003,2024-03-02,north,bag,accessories,2,850.0
1004,2024-03-02,east,bottle,accessories,7,120.0
1005,2024-03-03,north,eraser,stationery,30,8.0
1006,2024-03-03,south,bag,accessories,1,850.0
1007,2024-03-04,east,pen,stationery,20,15.0
1008,2024-03-04,north,bottle,accessories,4,120.0
"""
orders = pd.read_csv(StringIO(RAW))
top = orders.sort_values("price", ascending=False)
print(list(top.index[:3]))- A[0, 1, 2]
- B[2, 5, 3]
- C[5, 2, 7]
- D[2, 5, 7]
लक्ष्य सबसे अधिक आइटम वाले ऑर्डर को प्रिंट करना है। क्या प्रिंट होगा?
from io import StringIO
import pandas as pd
# Stands in for orders.csv, so this snippet runs on its own.
RAW = """order_id,date,branch,product,category,quantity,price
1001,2024-03-01,north,pen,stationery,12,15.0
1002,2024-03-01,south,notebook,stationery,5,60.0
1003,2024-03-02,north,bag,accessories,2,850.0
1004,2024-03-02,east,bottle,accessories,7,120.0
1005,2024-03-03,north,eraser,stationery,30,8.0
1006,2024-03-03,south,bag,accessories,1,850.0
1007,2024-03-04,east,pen,stationery,20,15.0
1008,2024-03-04,north,bottle,accessories,4,120.0
"""
orders = pd.read_csv(StringIO(RAW))
orders.sort_values("quantity", ascending=False)
print(orders.iloc[0]["order_id"])- A1005
- B1001 — `sort_values` ने सॉर्ट की हुई कॉपी लौटाई और उसे किसी वेरिएबल में सहेजा नहीं गया
- C1007
- Dएक `TypeError`: परिणाम को असाइन करना अनिवार्य है
आप ऑर्डर्स को ब्रांच के अनुसार A–Z क्रम में और प्रत्येक ब्रांच के भीतर सबसे बड़ी संख्या (quantity) पहले रखना चाहते हैं। कौन सी लाइन यह काम करेगी?
- Aorders.sort_values(["branch", "quantity"], ascending=False)
- Borders.sort_values(["quantity", "branch"], ascending=[False, True])
- Corders.sort_values("branch").sort_values("quantity", ascending=False)
- Dorders.sort_values(["branch", "quantity"], ascending=[True, False])
उत्तर देने के लिए अकाउंट आवश्यक है
अपने उत्तर जाँचने के लिए साइन इन करें
प्रश्न ऊपर दिए गए हैं, और मन में उत्तर सोचना ही मुख्य कार्य है। सही उत्तर, व्याख्या और तीन-स्तरीय संकेत देखने के लिए साइन इन करें।
आपकी बारी
एक शिक्षक आपको एक परीक्षा के अंक भेजते हैं। इसे results.csv के रूप में सहेजें। दो छात्रों के पास अभी तक कोई अंक नहीं है, और कुछ नाम लोअरकेस में टाइप किए गए थे:
name,section,marks
Rafi,B,78
anika,A,91
Tanvir,A,
Mitu,B,91
zara,A,65
Karim,B,
Nadia,A,88
Sabbir,B,54ranking.py लिखें। किसी भी कोड से पहले, फ़ाइल के शीर्ष पर टिप्पणियों के रूप में योजना लिखें: प्रत्येक सूची के लिए की कॉलम, दिशा, टाई कैसे तोड़ी जाती है और रिक्तियाँ कहाँ जाती हैं। फिर प्रोग्राम को इन चार शर्तों को पूरा करने दें:
- कुछ भी सॉर्ट करने से पहले, यह
shape,dtypesऔर अनुपस्थित अंकों की संख्या प्रिंट करता है। - यह एक मेरिट सूची (merit list) प्रिंट करता है: उच्चतम अंक पहले, बिना अंक वाले छात्र सबसे नीचे, अंकों पर टाई होने पर केस की परवाह किए बिना नाम के वर्णानुक्रम में टाई तोड़ा जाए, और पंक्तियों को 0, 1, 2, … से पुनः क्रमांकित किया जाए।
- यह
nlargestके साथ शीर्ष तीन प्रिंट करता है, तीसरे स्थान पर टाई होने वाले सभी को सूची में बनाए रखता है। - यह बिना अंक वाले छात्रों को केस की परवाह किए बिना नाम के क्रम में प्रिंट करता है, ताकि शिक्षक उनसे संपर्क कर सकें — और फिर मूल टेबल, यह साबित करने के लिए कि इसे कभी बदला नहीं गया था।
आपके प्रोग्राम को बिल्कुल यह प्रिंट करना चाहिए:
(8, 3)
name str
section str
marks float64
dtype: object
Missing marks: 2
Merit list
name section marks
0 anika A 91.0
1 Mitu B 91.0
2 Nadia A 88.0
3 Rafi B 78.0
4 zara A 65.0
5 Sabbir B 54.0
6 Karim B NaN
7 Tanvir A NaN
Top three
name section marks
1 anika A 91.0
3 Mitu B 91.0
6 Nadia A 88.0
No mark yet
name section marks
5 Karim B NaN
2 Tanvir A NaN
Original, unchanged
name section marks
0 Rafi B 78.0
1 anika A 91.0
2 Tanvir A NaN
3 Mitu B 91.0
4 zara A 65.0
5 Karim B NaN
6 Nadia A 88.0
7 Sabbir B 54.0फिर मेरिट सूची पर दो प्रयोग करके देखें:
key=हटा दें। 91 अंक वाले दो छात्रों में से अब कौन पहले आता है, और क्यों?- कीज़ में से
"name"को पूरी तरह हटा दें और केवलmarksके आधार पर सॉर्ट करें। 91 पर कौन पहले आता है — और क्या यह परिणाम सुनिश्चित है?
समाधान
योजना। फ़ाइल में 8 छात्र और 3 कॉलम हैं। marks में रिक्तियाँ हैं, इसलिए इसे float64 के रूप में पढ़ा जाएगा, और अंकों के आधार पर सॉर्ट करने वाली प्रत्येक सूची को यह बताना होगा कि रिक्तियाँ कहाँ जाएँगी। name में बड़े और छोटे अक्षर मिले हुए हैं, इसलिए नामों की प्रत्येक तुलना के लिए key= की आवश्यकता है।
- मेरिट सूची — कीज़
marks, फिरname; अंक उच्च से निम्न, नाम A से Z; अंकों पर टाई नाम से तोड़ी जाती है; रिक्तियाँ अंत में (डिफ़ॉल्ट);reset_index(drop=True)से पुनः क्रमांकित। - शीर्ष तीन —
keep="all"के साथnlargest(3, "marks"), ताकि साझा तीसरा स्थान कटे नहीं।nlargestअपने आप रिक्तियों को छोड़ देता है। - बिना अंक वाले छात्र — उन पंक्तियों को फ़िल्टर करें जहाँ
marksगायब हैं, जैसा कि पहले के अध्यायों में किया गया था, फिर नाम से सॉर्ट करें। पहले फ़िल्टर करें, फिर सॉर्ट करें। - मूल टेबल — कभी भी पुनः असाइन नहीं किया गया, इसलिए अंत में
resultsप्रिंट करने पर फ़ाइल का क्रम दिखाई देता है।
एक विवरण: एक key= फ़ंक्शन प्रत्येक की कॉलम पर लागू होता है। मेरिट सूची के लिए इसका मतलब marks भी है, और संख्याओं पर .str.lower() विफल हो जाएगा। इसलिए फ़ंक्शन केवल टेक्स्ट कॉलमों को लोअरकेस करता है और किसी भी अन्य कॉलम को अपरिवर्तित लौटाता है।
ranking.py:
import pandas as pd
# Merit list : marks high->low, ties by name A->Z ignoring case, blanks last, renumber
# Top three : nlargest on marks, keep="all" so a shared third place is not cut
# No mark yet : filter rows with no mark, then name A->Z ignoring case
# Original : never reassigned
results = pd.read_csv("results.csv")
print(results.shape)
print(results.dtypes)
print("Missing marks:", results["marks"].isna().sum())
print()
def lower_text(col):
return col.str.lower() if col.dtype == "str" else col
merit = results.sort_values(
["marks", "name"], ascending=[False, True], key=lower_text
).reset_index(drop=True)
print("Merit list")
print(merit)
print()
print("Top three")
print(results.nlargest(3, "marks", keep="all"))
print()
print("No mark yet")
missing = results[results["marks"].isna()]
print(missing.sort_values("name", key=lower_text))
print()
print("Original, unchanged")
print(results)(8, 3)
name str
section str
marks float64
dtype: object
Missing marks: 2
Merit list
name section marks
0 anika A 91.0
1 Mitu B 91.0
2 Nadia A 88.0
3 Rafi B 78.0
4 zara A 65.0
5 Sabbir B 54.0
6 Karim B NaN
7 Tanvir A NaN
Top three
name section marks
1 anika A 91.0
3 Mitu B 91.0
6 Nadia A 88.0
No mark yet
name section marks
5 Karim B NaN
2 Tanvir A NaN
Original, unchanged
name section marks
0 Rafi B 78.0
1 anika A 91.0
2 Tanvir A NaN
3 Mitu B 91.0
4 zara A 65.0
5 Karim B NaN
6 Nadia A 88.0
7 Sabbir B 54.0योजना के विरुद्ध आउटपुट को पढ़ना:
marksका प्रकारfloat64है,int64नहीं, औरMissing marks: 2— किसी भी रैंकिंग से पहले रिक्तियाँ पाई गईं, ताकि मेरिट सूची का पाठक जान सके कि दो छात्र इसमें अनुपस्थित हैं, वे इसके निचले भाग में नहीं हैं।- 91 पर टाई नाम से तय होती है।
anika,Mituसे पहले आती है क्योंकि तुलना"anika"और"mitu"पर की गई थी। - शीर्ष तीन में यहाँ तीन पंक्तियाँ हैं, क्योंकि तीसरा स्थान (88) साझा नहीं है। यदि नादिया के भी 91 होते, तो किसी छात्र को चुपचाप छोड़ने के बजाय
keep="all"चार पंक्तियाँ लौटाता। - बिना अंक वाली सूची पहले फ़िल्टर करती है, फिर सॉर्ट करती है — वही "पहले सीमित करें, फिर रैंक करें" क्रम जैसा कि किसी सबसेट के शीर्ष-N पैटर्न में होता है।
- अंतिम तालिका फ़ाइल का क्रम है। तीन सूचियाँ तैयार की गईं, और
resultsको कभी भी पुनः असाइन नहीं किया गया।
प्रयोग:
no_key = results.sort_values(["marks", "name"], ascending=[False, True])
marks_only = results.sort_values("marks", ascending=False)
print(no_key["name"].head(2).tolist())
print(marks_only["name"].head(2).tolist())['Mitu', 'anika']
['anika', 'Mitu']key= के बिना, नामों की तुलना अक्षर-दर-अक्षर की जाती है, और प्रत्येक बड़ा अक्षर प्रत्येक छोटे अक्षर से पहले आता है, इसलिए "Mitu", "anika" से आगे निकल जाता है — यह क्रम इस बात पर आधारित है कि नाम कैसे टाइप किया गया था, वर्णमाला पर नहीं। अकेले marks के साथ, anika संयोग से पहले आती है क्योंकि वह फ़ाइल में पहले थी। यह सही मेरिट सूची के समान ही उत्तर है, लेकिन केवल संयोगवश: एक अकेले की के साथ डिफ़ॉल्ट सॉर्ट टाई पंक्तियों को फ़ाइल क्रम में रखने का वादा नहीं करता है, जैसा कि 120 वाली दो बोतलों ने पहले दिखाया था। आपके द्वारा लिखा गया नियम निश्चित होता है; वह परिणाम जो केवल सही दिखता है, निश्चित नहीं होता।
Step 6 of 6
चुनौती — the chapter quiz
सरल से कठिन — दस प्रश्न, अंतिम वाले जानबूझकर चुनौतीपूर्ण बनाए गए हैं।
Sign in to take the quiz