Филтри и подреждане
Накратко: Филтрирането в pandas пази само редовете, за които маската е True (или isin, between, query), а sort_values ги подрежда по колона.
Проблем
Списъкът за доставчика
Доставчикът на храни идва утре. Управителят иска списък: храните, от които имаме по-малко от 20 броя, като най-спешните са първи. После пита и за поръчките през годината: колко са отказани и колко клиенти ни купуват редовно.
25 продукта можеш да прегледаш с очи. Поръчките за годината са 11 116, и там очите не стигат. Трябва ти начин да кажеш на таблицата „дай ми само тези редове“ и „подреди ги така“.
Идеята
Маска върху таблица
Маската от NumPy работи и в pandas. products['stock'] < 20 сравнява всеки ред и дава колона (Series) от True и False, с индекса на таблицата. Сложена в квадратни скоби, маската оставя редовете с True:
low.sum() брои истините: 9 продукта са под 20 броя. Това се казва филтър: таблица само с редовете, за които условието е вярно.
Виж индекса вляво: 3, 6, 7, 12… Редовете пазят етикетите си от products, затова винаги знаеш откъде е дошъл всеки. В [] името на колона избира колона, а маската избира редове.
Идеята
Две условия: &, | и ~
Под 20 броя и под 5 € са две условия заедно. С and става същото като в NumPy:
and иска едно True или False, а колоната има 25. Затова и тук пишеш & за „и“, | за „или“ и ~ за „не“, с всяко условие в скоби:
Под 20 броя и под 5 € са баницата и краставиците, и двете изчерпани. Под 1 € или над 20 € са кифлата (0,80 €), водата (0,90 €), тиганът (24,90 €) и ножовете (39 €). Подаръчната карта е точно 20 € и не е „над 20“.
Пробвай
Скъпите млечни
Кои млечни продукти (категория 4) струват над 3 €? Запиши таблицата с тях в pricey_dairy.
Решение
import pandas as pd
products = pd.read_csv('products.csv')
pricey_dairy = products[(products['category_id'] == 4) & (products['price'] > 3)]
pricey_dairy[['name', 'price']]products[(products['category_id'] == 4) & (products['price'] > 3)] дава 3 продукта: сиренето (7,90 €), кашкавала (9,50 €) и маслото (3,20 €). С | влизат всички млечни и всичко над 3 €, а без скобите кодът пада с грешка. Самата маска, без products[...], е само колона от True и False.
Идеята
От списък и между две числа: isin и between
Храните са в четири категории: 3, 4, 5 и 6. Вместо четири условия с | пишеш isin, което пита „в този списък ли е?“:
Храните са 18. С ~ получаваш останалите 7: шестте продукта за дома и подаръчната карта. Картата няма категория (NaN), а NaN не е в никой списък, затова ~ я хваща.
За интервал има between. between(2, 5) е „от 2 до 5 включително“, двата края влизат:
Излизат 9 продукта, колкото с (prices >= 2) & (prices <= 5) в урока за NumPy.
По-точно, за любопитните
between(2, 5, inclusive='neither') изключва двата края, а 'left' и 'right' оставят само единия. По подразбиране е 'both'.
Идеята
Текст, който съдържа: str.contains
„Покажи ми всички хлябове.“ В имената има „Бял хляб“ и „Пълнозърнест хляб“, но не можеш да напишеш == 'хляб': никое име не е точно „хляб“. str.contains пита дали текстът се съдържа някъде в името:
.str отваря методите за текст на цялата колона. Ще го видиш по-подробно в урока за типовете.
Търсенето различава главни и малки букви. „сирене“ намира само „Баница със сирене“, затова първото число е 1. „Сирене“ е с главно С и не влиза. С case=False буквите не се различават и излизат 2.
Идеята
Условието като текст: query
Дълги маски с products['...'] навсякъде стават трудни за четене. query взима условието като текст, в който имената на колоните стоят сами:
В query пишеш and, or и not. Текстът не се смята от Python, а от pandas, и той знае, че става дума за колони. Под 20 броя и над 5 € са 7 продукта.
Променлива от Python влиза с @: category_id in @food е същото като isin(food). Така излизат петте храни под 20 броя, от които ще направиш списъка за доставчика.
Идеята
Подреждане: sort_values и nlargest
sort_values('price') подрежда редовете по цена, от малката към голямата. С ascending=False е обратно. За „първите N“ има nlargest(N, колона) и nsmallest:
Най-скъпи са ножовете (39 €), тиганът (24,90 €) и подаръчната карта (20 €). nlargest(3, 'price') дава същите три на един ред.
Можеш да подредиш и по няколко колони: първо по категория, а вътре в нея по цена. ascending тогава е списък, по едно за всяка колона. Категориите вървят нагоре, а цените в тях надолу: баницата (2,50 €) е първа в хляба, кашкавалът (9,50 €) в млечните.
По-точно, за любопитните
Подреждането мести редовете, но не им сменя етикетите: индексът в изхода е 22, 21, 24… Ако ти трябват номера 0, 1, 2 в новия ред, добави .reset_index(drop=True).
Идеята
Колко от всяко: value_counts
„Колко поръчки са отказани?“ е въпрос за броене. value_counts брои колко пъти се среща всяка стойност в колона, най-честата отгоре:
От 11 116 поръчки за годината 10 254 са доставени, а 657 са отказани. С normalize=True получаваш дял вместо брой: 0,059, тоест 5,9% от поръчките са отказани.
Същото върху номера на клиента казва кой колко пъти е поръчал:
Поръчвали са 1 390 клиенти. Най-верният, клиент 1, е поръчал 121 пъти, а 224 клиенти са поръчали само веднъж. Индексът на резултата са номерата на клиентите, а стойностите са броят на поръчките им.
Пробвай
Отворените поръчки
Поръчките със статус new, paid или shipped още не са стигнали до клиента. Запиши таблицата с тях в open_orders.
Решение
import pandas as pd
year = pd.read_csv('year_orders.csv')
open_orders = year[year['status'].isin(['new', 'paid', 'shipped'])]
print(len(open_orders))year[year['status'].isin(['new', 'paid', 'shipped'])] дава 205 поръчки: 90 нови, 63 платени и 52 изпратени, точно колкото казва value_counts. != 'delivered' би сложил вътре и 657-те отказани, а те няма да тръгнат.
Упражнение
Списъкът и редовните клиенти
Направи списъка за доставчика: храните (категории 3, 4, 5 и 6) с наличност под 20, подредени по наличност от най-малката. При равна наличност по-скъпият продукт е първи. Запиши таблицата в restock.
Решение
import pandas as pd
products = pd.read_csv('products.csv')
food = [3, 4, 5, 6]
restock = products[products['category_id'].isin(food) & (products['stock'] < 20)]
restock = restock.sort_values(['stock', 'price'], ascending=[True, False])
restock[['name', 'price', 'stock']]Филтърът isin(food) & (stock < 20) дава 5 храни. sort_values(['stock', 'price'], ascending=[True, False]) ги нарежда: краставиците (2,80 €, 0 броя), баницата (2,50 €, 0 броя), кашкавалът (12 броя), кафето (15) и сиренето (18). Без isin в списъка влизат и тиганът, ножовете, дъската за рязане и прахът за пране, а с ascending=False за двете колони най-спешните отиват най-долу.
Колко клиенти са поръчали поне 20 пъти през годината? Запиши броя им в regulars.
Решение
import pandas as pd
year = pd.read_csv('year_orders.csv')
per_customer = year['customer_id'].value_counts()
regulars = (per_customer >= 20).sum()
print(regulars)per_customer = year['customer_id'].value_counts() дава броя поръчки на всеки клиент, а (per_customer >= 20).sum() брои клиентите с поне 20: те са 119. (year['customer_id'] >= 20).sum() дава 9 471, защото сравнява номерата на клиентите, а не поръчките им. С > 20 излизат 110: изпускаш тези с точно 20.
Тест
Провери се
Свързани уроци
Раздел „Свързани уроци“- Нужно отпреди: Векторизация · Обобщения и липсващи стойности · Series и DataFrame · Избиране: [], loc и iloc
- Продължава в: Нови колони · Типове и липсващи стойности · Групи: groupby · Съединяване: merge
- Задачи по темата: Таблици с pandas