Aby dokonywać "biznesowej analizy danych", użyjemy biblioteki pandas
. Dodatkowo zaimportujemy też numpy
, ale zwykle nie ma takiej potrzeby. Konwencją jest, że zaimportowanym modułom nadaje się skrótowe nazwy pd
oraz np
.
import numpy as np
import pandas as pd
Wczytanie danych¶
Zwykle na początku wczytujemy dane z zewnętrznego źródła. Zwykle jest to plik csv, ale Pandas potrafi też czytać pliki Excel i wiele innych oraz pobierać dane z baz SQL.
# to wczytuje dane w podstawowy sposób
# emps = pd.read_csv('pliki/emps.csv', sep=';')
# teraz dodamy kolejne ustawienia:
emps = pd.read_csv('pliki/emps.csv', sep=';', index_col='employee_id', parse_dates=['hire_date'])
emps
first_name | last_name | job_title | salary | hire_date | department_name | address | postal_code | city | country | |
---|---|---|---|---|---|---|---|---|---|---|
employee_id | ||||||||||
100 | Steven | King | President | 24000 | 1997-06-17 | Executive | 2004 Charade Rd | 98199 | Seattle | United States of America |
101 | Neena | Kochhar | Administration Vice President | 17000 | 1999-09-21 | Executive | 2004 Charade Rd | 98199 | Seattle | United States of America |
102 | Lex | De Haan | Administration Vice President | 17000 | 2003-01-13 | Executive | 2004 Charade Rd | 98199 | Seattle | United States of America |
103 | Alexander | Hunold | Programmer | 9000 | 2000-01-03 | IT | 2014 Jabberwocky Rd | 26192 | Southlake | United States of America |
104 | Bruce | Ernst | Programmer | 6000 | 2001-05-21 | IT | 2014 Jabberwocky Rd | 26192 | Southlake | United States of America |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
202 | Pat | Fay | Marketing Representative | 6000 | 2007-08-17 | Marketing | 147 Spadina Ave | M5V 2L7 | Toronto | Canada |
203 | Susan | Mavris | Human Resources Representative | 6500 | 2004-06-07 | Human Resources | 8204 Arthur St | NaN | London | United Kingdom |
204 | Hermann | Baer | Public Relations Representative | 10000 | 2004-06-07 | Public Relations | Schwanthalerstr. 7031 | 80925 | Munich | Germany |
205 | Shelley | Higgins | Accounting Manager | 12000 | 2004-06-07 | Accounting | 2004 Charade Rd | 98199 | Seattle | United States of America |
206 | William | Gietz | Public Accountant | 8300 | 2004-06-07 | Accounting | 2004 Charade Rd | 98199 | Seattle | United States of America |
107 rows × 10 columns
Wczytamy jeszcze drugi plik...
sprzedaz = pd.read_csv('pliki/sprzedaz.csv', sep=',', parse_dates=['data'])
sprzedaz
data | miasto | sklep | kategoria | towar | cena | sztuk | |
---|---|---|---|---|---|---|---|
0 | 2014-11-23 | Łódź | Wdowiak | meble | biurko | 149.99 | 4 |
1 | 2017-05-07 | Radom | Czarnecki | wyposażenie szkolne | tablica | 590.00 | 2 |
2 | 2017-05-05 | Kraków | Kozłowski | szkolno-biurowe | flamaster | 0.99 | 51 |
3 | 2016-10-19 | Kraków | Wróbel | wyposażenie szkolne | gąbka | 4.00 | 250 |
4 | 2016-04-08 | Poznań | Borowik | meble | biurko | 149.99 | 9 |
... | ... | ... | ... | ... | ... | ... | ... |
9995 | 2016-05-22 | Katowice | Gaińska | szkolno-biurowe | dziurkacz | 7.50 | 178 |
9996 | 2016-11-19 | Kraków | Kozłowski | meble | biurko | 149.99 | 7 |
9997 | 2016-09-30 | Łódź | Wdowiak | szkolno-biurowe | długopis | 1.49 | 87 |
9998 | 2015-05-01 | Kraków | Kozłowski | meble | biurko | 149.99 | 10 |
9999 | 2016-08-26 | Kraków | Kozłowski | wyposażenie szkolne | gąbka | 4.00 | 152 |
10000 rows × 7 columns
Typy danych itp.¶
Tabela z danymi, coś, co odpowiada arkuszowi Excela albo tabeli bazodanowej, to jest DataFrame
.
type(emps)
pandas.core.frame.DataFrame
Pojedyncza kolumna, „seria danych” jest typu Series
.
type(emps.last_name)
pandas.core.series.Series
Jakie typu są kolumny?
sprzedaz.dtypes
data datetime64[ns] miasto object sklep object kategoria object towar object cena float64 sztuk int64 dtype: object
Nazwy kolumn:
sprzedaz.columns
Index(['data', 'miasto', 'sklep', 'kategoria', 'towar', 'cena', 'sztuk'], dtype='object')
sprzedaz.columns[2]
'sklep'
emps.shape
(107, 10)
emps.size
1070
len(emps)
107
Indeksowanie¶
czyli dostęp po współrzędnych.
.iloc
- dostęp wg współrzędnych numerycznych, jak wnumpy
, numeracja od zera.loc
- dostęp wg wartości indeksu i nazwy kolumny
emps.iloc[0, 0]
'Steven'
emps.iloc[2, 3]
17000
DataFrame
i Series
są „mutowalne”.
emps.iloc[0, 3] += 1
emps.head(5)
first_name | last_name | job_title | salary | hire_date | department_name | address | postal_code | city | country | |
---|---|---|---|---|---|---|---|---|---|---|
employee_id | ||||||||||
100 | Steven | King | President | 24001 | 1997-06-17 | Executive | 2004 Charade Rd | 98199 | Seattle | United States of America |
101 | Neena | Kochhar | Administration Vice President | 17000 | 1999-09-21 | Executive | 2004 Charade Rd | 98199 | Seattle | United States of America |
102 | Lex | De Haan | Administration Vice President | 17000 | 2003-01-13 | Executive | 2004 Charade Rd | 98199 | Seattle | United States of America |
103 | Alexander | Hunold | Programmer | 9000 | 2000-01-03 | IT | 2014 Jabberwocky Rd | 26192 | Southlake | United States of America |
104 | Bruce | Ernst | Programmer | 6000 | 2001-05-21 | IT | 2014 Jabberwocky Rd | 26192 | Southlake | United States of America |
emps.iloc[20:30, :4]
first_name | last_name | job_title | salary | |
---|---|---|---|---|
employee_id | ||||
120 | Matthew | Weiss | Stock Manager | 8000 |
121 | Adam | Fripp | Stock Manager | 8200 |
122 | Payam | Kaufling | Stock Manager | 7900 |
123 | Shanta | Vollman | Stock Manager | 6500 |
124 | Kevin | Mourgos | Stock Manager | 5800 |
125 | Julia | Nayer | Stock Clerk | 3200 |
126 | Irene | Mikkilineni | Stock Clerk | 2700 |
127 | James | Landry | Stock Clerk | 2400 |
128 | Steven | Markle | Stock Clerk | 2200 |
129 | Laura | Bissot | Stock Clerk | 3300 |
.loc
to dostęp wg indeksu „biznesowego” i nazw kolumn
emps.loc[101, 'last_name']
'Kochhar'
emps.loc[102:105, 'first_name':'salary']
first_name | last_name | job_title | salary | |
---|---|---|---|---|
employee_id | ||||
102 | Lex | De Haan | Administration Vice President | 17000 |
103 | Alexander | Hunold | Programmer | 9000 |
104 | Bruce | Ernst | Programmer | 6000 |
105 | David | Austin | Programmer | 4800 |
emps.loc[:105, ['first_name', 'last_name', 'salary', 'city']]
first_name | last_name | salary | city | |
---|---|---|---|---|
employee_id | ||||
100 | Steven | King | 24001 | Seattle |
101 | Neena | Kochhar | 17000 | Seattle |
102 | Lex | De Haan | 17000 | Seattle |
103 | Alexander | Hunold | 9000 | Southlake |
104 | Bruce | Ernst | 6000 | Southlake |
105 | David | Austin | 4800 | Southlake |
Odczyt całej wybranej kolumny jest jeszcze prostszy:
- notacja obiektowa, dostępna tylko jeśli w nazwie kolumny nie ma spacji ani innych znaków specjalnych:
emps.salary
employee_id 100 24001 101 17000 102 17000 103 9000 104 6000 ... 202 6000 203 6500 204 10000 205 12000 206 8300 Name: salary, Length: 107, dtype: int64
- notacja słownikowa
emps['hire_date']
employee_id 100 1997-06-17 101 1999-09-21 102 2003-01-13 103 2000-01-03 104 2001-05-21 ... 202 2007-08-17 203 2004-06-07 204 2004-06-07 205 2004-06-07 206 2004-06-07 Name: hire_date, Length: 107, dtype: datetime64[ns]
emps[['last_name', 'hire_date']]
last_name | hire_date | |
---|---|---|
employee_id | ||
100 | King | 1997-06-17 |
101 | Kochhar | 1999-09-21 |
102 | De Haan | 2003-01-13 |
103 | Hunold | 2000-01-03 |
104 | Ernst | 2001-05-21 |
... | ... | ... |
202 | Fay | 2007-08-17 |
203 | Mavris | 2004-06-07 |
204 | Baer | 2004-06-07 |
205 | Higgins | 2004-06-07 |
206 | Gietz | 2004-06-07 |
107 rows × 2 columns
Iteracja po wszystkich wierszach
(w praktyce rzadko stosowane, jeśli już, to w programie .py
, a nie w Jupyter Notebook).
for idx, row in emps.iterrows():
print(f'Osoba {row.first_name} {row.last_name} zarabia {row["salary"]}')
Osoba Steven King zarabia 24001 Osoba Neena Kochhar zarabia 17000 Osoba Lex De Haan zarabia 17000 Osoba Alexander Hunold zarabia 9000 Osoba Bruce Ernst zarabia 6000 Osoba David Austin zarabia 4800 Osoba Valli Pataballa zarabia 4800 Osoba Diana Lorentz zarabia 4200 Osoba Nancy Greenberg zarabia 12000 Osoba Daniel Faviet zarabia 9000 Osoba John Chen zarabia 8200 Osoba Ismael Sciarra zarabia 7700 Osoba Jose Manuel Urman zarabia 7800 Osoba Luis Popp zarabia 6900 Osoba Den Raphaely zarabia 11000 Osoba Alexander Khoo zarabia 3100 Osoba Shelli Baida zarabia 2900 Osoba Sigal Tobias zarabia 2800 Osoba Guy Himuro zarabia 2600 Osoba Karen Colmenares zarabia 2500 Osoba Matthew Weiss zarabia 8000 Osoba Adam Fripp zarabia 8200 Osoba Payam Kaufling zarabia 7900 Osoba Shanta Vollman zarabia 6500 Osoba Kevin Mourgos zarabia 5800 Osoba Julia Nayer zarabia 3200 Osoba Irene Mikkilineni zarabia 2700 Osoba James Landry zarabia 2400 Osoba Steven Markle zarabia 2200 Osoba Laura Bissot zarabia 3300 Osoba Mozhe Atkinson zarabia 2800 Osoba James Marlow zarabia 2500 Osoba TJ Olson zarabia 2100 Osoba Jason Mallin zarabia 3300 Osoba Michael Rogers zarabia 2900 Osoba Ki Gee zarabia 2400 Osoba Hazel Philtanker zarabia 2200 Osoba Renske Ladwig zarabia 3600 Osoba Stephen Stiles zarabia 3200 Osoba John Seo zarabia 2700 Osoba Joshua Patel zarabia 2500 Osoba Trenna Rajs zarabia 3500 Osoba Curtis Davies zarabia 3100 Osoba Randall Matos zarabia 2600 Osoba Peter Vargas zarabia 2500 Osoba John Russell zarabia 14000 Osoba Karen Partners zarabia 13500 Osoba Alberto Errazuriz zarabia 12000 Osoba Gerald Cambrault zarabia 11000 Osoba Eleni Zlotkey zarabia 10500 Osoba Peter Tucker zarabia 10000 Osoba David Bernstein zarabia 9500 Osoba Peter Hall zarabia 9000 Osoba Christopher Olsen zarabia 8000 Osoba Nanette Cambrault zarabia 7500 Osoba Oliver Tuvault zarabia 7000 Osoba Janette King zarabia 10000 Osoba Patrick Sully zarabia 9500 Osoba Allan McEwen zarabia 9000 Osoba Lindsey Smith zarabia 8000 Osoba Louise Doran zarabia 7500 Osoba Sarath Sewall zarabia 7000 Osoba Clara Vishney zarabia 10500 Osoba Danielle Greene zarabia 9500 Osoba Mattea Marvins zarabia 7200 Osoba David Lee zarabia 6800 Osoba Sundar Ande zarabia 6400 Osoba Amit Banda zarabia 6200 Osoba Lisa Ozer zarabia 11500 Osoba Harrison Bloom zarabia 10000 Osoba Tayler Fox zarabia 9600 Osoba William Smith zarabia 7400 Osoba Elizabeth Bates zarabia 7300 Osoba Sundita Kumar zarabia 6100 Osoba Ellen Abel zarabia 11000 Osoba Alyssa Hutton zarabia 8800 Osoba Jonathon Taylor zarabia 8600 Osoba Jack Livingston zarabia 8400 Osoba Kimberely Grant zarabia 7000 Osoba Charles Johnson zarabia 6200 Osoba Winston Taylor zarabia 3200 Osoba Jean Fleaur zarabia 3100 Osoba Martha Sullivan zarabia 2500 Osoba Girard Geoni zarabia 2800 Osoba Nandita Sarchand zarabia 4200 Osoba Alexis Bull zarabia 4100 Osoba Julia Dellinger zarabia 3400 Osoba Anthony Cabrio zarabia 3000 Osoba Kelly Chung zarabia 3800 Osoba Jennifer Dilly zarabia 3600 Osoba Timothy Gates zarabia 2900 Osoba Randall Perkins zarabia 2500 Osoba Sarah Bell zarabia 4000 Osoba Britney Everett zarabia 3900 Osoba Samuel McCain zarabia 3200 Osoba Vance Jones zarabia 2800 Osoba Alana Walsh zarabia 3100 Osoba Kevin Feeney zarabia 3000 Osoba Donald OConnell zarabia 2600 Osoba Douglas Grant zarabia 2600 Osoba Jennifer Whalen zarabia 4400 Osoba Michael Hartstein zarabia 13000 Osoba Pat Fay zarabia 6000 Osoba Susan Mavris zarabia 6500 Osoba Hermann Baer zarabia 10000 Osoba Shelley Higgins zarabia 12000 Osoba William Gietz zarabia 8300
Filtrowanie danych¶
zwn warunek logiczny
emps[emps.salary >= 15000]
first_name | last_name | job_title | salary | hire_date | department_name | address | postal_code | city | country | |
---|---|---|---|---|---|---|---|---|---|---|
employee_id | ||||||||||
100 | Steven | King | President | 24001 | 1997-06-17 | Executive | 2004 Charade Rd | 98199 | Seattle | United States of America |
101 | Neena | Kochhar | Administration Vice President | 17000 | 1999-09-21 | Executive | 2004 Charade Rd | 98199 | Seattle | United States of America |
102 | Lex | De Haan | Administration Vice President | 17000 | 2003-01-13 | Executive | 2004 Charade Rd | 98199 | Seattle | United States of America |
Technicznie operacja emps.salary >= 15000
daje w wyniku serię wartości True/False
emps.salary >= 15000
employee_id 100 True 101 True 102 True 103 False 104 False ... 202 False 203 False 204 False 205 False 206 False Name: salary, Length: 107, dtype: bool
warunki = emps.salary >= 15000
Gdy do nawiasów kwadratowych przekażemy taką serię, to w wyniku dostajemy te rekordy, dla których na odp pozycji było True.
emps[warunki]
first_name | last_name | job_title | salary | hire_date | department_name | address | postal_code | city | country | |
---|---|---|---|---|---|---|---|---|---|---|
employee_id | ||||||||||
100 | Steven | King | President | 24001 | 1997-06-17 | Executive | 2004 Charade Rd | 98199 | Seattle | United States of America |
101 | Neena | Kochhar | Administration Vice President | 17000 | 1999-09-21 | Executive | 2004 Charade Rd | 98199 | Seattle | United States of America |
102 | Lex | De Haan | Administration Vice President | 17000 | 2003-01-13 | Executive | 2004 Charade Rd | 98199 | Seattle | United States of America |
Złożone warunki logiczne¶
Tylko za pomocą operatorów &
i |
emps[(emps.job_title == 'Programmer') & (emps.salary >= 5000)]
first_name | last_name | job_title | salary | hire_date | department_name | address | postal_code | city | country | |
---|---|---|---|---|---|---|---|---|---|---|
employee_id | ||||||||||
103 | Alexander | Hunold | Programmer | 9000 | 2000-01-03 | IT | 2014 Jabberwocky Rd | 26192 | Southlake | United States of America |
104 | Bruce | Ernst | Programmer | 6000 | 2001-05-21 | IT | 2014 Jabberwocky Rd | 26192 | Southlake | United States of America |
emps.salary.mean()
6461.691588785046
emps.salary.min(), emps.salary.max(), emps.salary.mean(), emps.salary.median(), emps.salary.sum(), emps.salary.count(), emps.salary.std()
(2100, 24001, 6461.691588785046, 6200.0, 691401, 107, 3909.408070359112)
Łącząc technikę filtrowania z wyliczaniem statystyk, można:
emps[emps.job_title == 'Programmer'].salary.mean()
5760.0
Ciekawostka - można też tak:
emps.salary[emps.job_title == 'Programmer'].mean()
5760.0
Funkcje liczące kilka rzeczy jednocześnie¶
emps.salary.describe()
count 107.000000 mean 6461.691589 std 3909.408070 min 2100.000000 25% 3100.000000 50% 6200.000000 75% 8900.000000 max 24001.000000 Name: salary, dtype: float64
emps.salary.describe(percentiles=[0.1, 0.2, 0.5])
count 107.000000 mean 6461.691589 std 3909.408070 min 2100.000000 10% 2560.000000 20% 2900.000000 50% 6200.000000 max 24001.000000 Name: salary, dtype: float64
emps.salary.describe(percentiles=np.arange(0, 1, 0.1))
count 107.000000 mean 6461.691589 std 3909.408070 min 2100.000000 0% 2100.000000 10% 2560.000000 20% 2900.000000 30% 3200.000000 40% 4040.000000 50% 6200.000000 60% 7260.000000 70% 8200.000000 80% 9500.000000 90% 11000.000000 max 24001.000000 Name: salary, dtype: float64
emps.city.describe()
count 106 unique 7 top South San Francisco freq 45 Name: city, dtype: object
emps.city.value_counts()
city South San Francisco 45 Oxford 34 Seattle 18 Southlake 5 Toronto 2 London 1 Munich 1 Name: count, dtype: int64
Operacja agg
pozwala obliczyć kilka funkcji agregujących dla tego samego zestawu danych.
Szczególnie użyteczna w połączeniu z grupowaniem, o którym za chwilę...
emps.salary.agg(['min', 'mean', 'max'])
min 2100.000000 mean 6461.691589 max 24001.000000 Name: salary, dtype: float64
emps[emps.job_title == 'Programmer'].salary.agg(['count', 'min', 'mean', 'median', 'max'])
count 5.0 min 4200.0 mean 5760.0 median 4800.0 max 9000.0 Name: salary, dtype: float64
Praca z przykładem sprzedaż¶
We wczytanej tabeli mamy kolumny cena
oraz sztuk
, a dopiero ich iloczyn zawiera info o wartości transakcji.
Do tabeli dodamy nową kolumnę wartosc
, która będzie zawierać iloczyn.
sprzedaz['wartosc'] = sprzedaz.cena * sprzedaz.sztuk
sprzedaz
data | miasto | sklep | kategoria | towar | cena | sztuk | wartosc | |
---|---|---|---|---|---|---|---|---|
0 | 2014-11-23 | Łódź | Wdowiak | meble | biurko | 149.99 | 4 | 599.96 |
1 | 2017-05-07 | Radom | Czarnecki | wyposażenie szkolne | tablica | 590.00 | 2 | 1180.00 |
2 | 2017-05-05 | Kraków | Kozłowski | szkolno-biurowe | flamaster | 0.99 | 51 | 50.49 |
3 | 2016-10-19 | Kraków | Wróbel | wyposażenie szkolne | gąbka | 4.00 | 250 | 1000.00 |
4 | 2016-04-08 | Poznań | Borowik | meble | biurko | 149.99 | 9 | 1349.91 |
... | ... | ... | ... | ... | ... | ... | ... | ... |
9995 | 2016-05-22 | Katowice | Gaińska | szkolno-biurowe | dziurkacz | 7.50 | 178 | 1335.00 |
9996 | 2016-11-19 | Kraków | Kozłowski | meble | biurko | 149.99 | 7 | 1049.93 |
9997 | 2016-09-30 | Łódź | Wdowiak | szkolno-biurowe | długopis | 1.49 | 87 | 129.63 |
9998 | 2015-05-01 | Kraków | Kozłowski | meble | biurko | 149.99 | 10 | 1499.90 |
9999 | 2016-08-26 | Kraków | Kozłowski | wyposażenie szkolne | gąbka | 4.00 | 152 | 608.00 |
10000 rows × 8 columns
Zadania:¶
- Oblicz sumę wartości transakcji w całym pliku
sprzedaz.wartosc.sum()
8049567.3
- Oblicz sumę wartości transakcji w Katowicach
sprzedaz[sprzedaz.miasto == 'Katowice'].wartosc.sum()
1456316.08
- Oblicz liczbę transakcji, sumę wartości (i jeśli dasz radę sumaryczną liczbę sztuk) dotyczących towaru biurko w Katowicach
sprzedaz[(sprzedaz.towar == 'biurko') & (sprzedaz.miasto == 'Katowice')].wartosc.agg(['count', 'sum'])
count 248.0 sum 391473.9 Name: wartosc, dtype: float64
Operację agg
można też zastosować dla DataFrame
i przekazać słownik, który mówi, jakiew funkcje mają być liczone dla jakich kolumn.
sprzedaz[(sprzedaz.towar == 'biurko') & (sprzedaz.miasto == 'Katowice')].agg({'sztuk': ['sum'], 'wartosc': ['count', 'sum']})
sztuk | wartosc | |
---|---|---|
sum | 2610.0 | 391473.9 |
count | NaN | 248.0 |
Grupowanie¶
Podział rekordów zwn wartość kolumny i dla każdej grupy obliczenie jednej statystyki:
emps.groupby('job_title').salary.mean()
job_title Accountant 7920.0 Accounting Manager 12000.0 Administration Assistant 4400.0 Administration Vice President 17000.0 Finance Manager 12000.0 Human Resources Representative 6500.0 Marketing Manager 13000.0 Marketing Representative 6000.0 President 24001.0 Programmer 5760.0 Public Accountant 8300.0 Public Relations Representative 10000.0 Purchasing Clerk 2780.0 Purchasing Manager 11000.0 Sales Manager 12200.0 Sales Representative 8350.0 Shipping Clerk 3215.0 Stock Clerk 2785.0 Stock Manager 7280.0 Name: salary, dtype: float64
Za pomocą agg
dla jednej kolumny, możemy obliczyć kilka funkcji jednocześnie:
emps.groupby('job_title').salary.agg(['count', 'min', 'median', 'max'])
count | min | median | max | |
---|---|---|---|---|
job_title | ||||
Accountant | 5 | 6900 | 7800.0 | 9000 |
Accounting Manager | 1 | 12000 | 12000.0 | 12000 |
Administration Assistant | 1 | 4400 | 4400.0 | 4400 |
Administration Vice President | 2 | 17000 | 17000.0 | 17000 |
Finance Manager | 1 | 12000 | 12000.0 | 12000 |
Human Resources Representative | 1 | 6500 | 6500.0 | 6500 |
Marketing Manager | 1 | 13000 | 13000.0 | 13000 |
Marketing Representative | 1 | 6000 | 6000.0 | 6000 |
President | 1 | 24001 | 24001.0 | 24001 |
Programmer | 5 | 4200 | 4800.0 | 9000 |
Public Accountant | 1 | 8300 | 8300.0 | 8300 |
Public Relations Representative | 1 | 10000 | 10000.0 | 10000 |
Purchasing Clerk | 5 | 2500 | 2800.0 | 3100 |
Purchasing Manager | 1 | 11000 | 11000.0 | 11000 |
Sales Manager | 5 | 10500 | 12000.0 | 14000 |
Sales Representative | 30 | 6100 | 8200.0 | 11500 |
Shipping Clerk | 20 | 2500 | 3100.0 | 4200 |
Stock Clerk | 20 | 2100 | 2700.0 | 3600 |
Stock Manager | 5 | 5800 | 7900.0 | 8200 |
Za pomocą agg
na poziomie tabeli, możemy obliczyć funkcje dotyczące różnych kolumn - do agg
przekazuje się słownik:
emps.groupby('job_title').agg({'salary': ['min', 'mean', 'max'], 'hire_date': ['min', 'max']})
salary | hire_date | ||||
---|---|---|---|---|---|
min | mean | max | min | max | |
job_title | |||||
Accountant | 6900 | 7920.0 | 9000 | 1998-03-07 | 2009-12-07 |
Accounting Manager | 12000 | 12000.0 | 12000 | 2004-06-07 | 2004-06-07 |
Administration Assistant | 4400 | 4400.0 | 4400 | 1987-09-17 | 1987-09-17 |
Administration Vice President | 17000 | 17000.0 | 17000 | 1999-09-21 | 2003-01-13 |
Finance Manager | 12000 | 12000.0 | 12000 | 2004-08-17 | 2004-08-17 |
Human Resources Representative | 6500 | 6500.0 | 6500 | 2004-06-07 | 2004-06-07 |
Marketing Manager | 13000 | 13000.0 | 13000 | 2006-02-17 | 2006-02-17 |
Marketing Representative | 6000 | 6000.0 | 6000 | 2007-08-17 | 2007-08-17 |
President | 24001 | 24001.0 | 24001 | 1997-06-17 | 1997-06-17 |
Programmer | 4200 | 5760.0 | 9000 | 2000-01-03 | 2009-02-07 |
Public Accountant | 8300 | 8300.0 | 8300 | 2004-06-07 | 2004-06-07 |
Public Relations Representative | 10000 | 10000.0 | 10000 | 2004-06-07 | 2004-06-07 |
Purchasing Clerk | 2500 | 2780.0 | 3100 | 2005-05-18 | 2009-08-10 |
Purchasing Manager | 11000 | 11000.0 | 11000 | 2004-12-07 | 2004-12-07 |
Sales Manager | 10500 | 12200.0 | 14000 | 2000-01-29 | 2009-10-15 |
Sales Representative | 6100 | 8350.0 | 11500 | 2000-02-23 | 2011-01-04 |
Shipping Clerk | 2500 | 3215.0 | 4200 | 2000-02-03 | 2010-01-13 |
Stock Clerk | 2100 | 2785.0 | 3600 | 2005-07-14 | 2011-02-06 |
Stock Manager | 5800 | 7280.0 | 8200 | 2005-05-01 | 2009-11-16 |
Grupowanie po wielu kryteriach¶
Na przykładzie sprzedaż
sprzedaz.groupby(['miasto', 'towar']).wartosc.sum()
miasto towar Białystok biurko 79344.71 dziurkacz 18345.00 długopis 5381.88 flamaster 4325.31 gąbka 22924.00 ... Łódź gąbka 78196.00 kreda 85040.00 krzesło obrotowe 169257.00 plastelina 46632.04 tablica 174050.00 Name: wartosc, Length: 72, dtype: float64
sprzedaz.groupby(['miasto', 'towar']).agg({'wartosc': 'sum'})
wartosc | ||
---|---|---|
miasto | towar | |
Białystok | biurko | 79344.71 |
dziurkacz | 18345.00 | |
długopis | 5381.88 | |
flamaster | 4325.31 | |
gąbka | 22924.00 | |
... | ... | ... |
Łódź | gąbka | 78196.00 |
kreda | 85040.00 | |
krzesło obrotowe | 169257.00 | |
plastelina | 46632.04 | |
tablica | 174050.00 |
72 rows × 1 columns
Powstaje lista wartości zindeksowana dwupoziomowym indeksem. Ponieważ w różnych miastach sprzedawane są towary tego samego rodzaju (powtarzają się), aż prosi się o przedstawienie wyników w dwóch wymiarach.
W Pandas w bardzo prosty sposób można tworzyć tabele przestawne - operacja pivot_table
.
sprzedaz.pivot_table(index='miasto', columns='towar', aggfunc='sum', values='wartosc')
towar | biurko | dziurkacz | długopis | flamaster | gąbka | kreda | krzesło obrotowe | plastelina | tablica |
---|---|---|---|---|---|---|---|---|---|
miasto | |||||||||
Białystok | 79344.71 | 18345.0 | 5381.88 | 4325.31 | 22924.0 | 30845.0 | 62445.0 | 16453.97 | 88500.0 |
Gdańsk | 291880.54 | 69937.5 | 20444.29 | 17970.48 | 89124.0 | 141335.0 | 281520.0 | 59533.89 | 211810.0 |
Katowice | 391473.90 | 111825.0 | 25130.34 | 21845.34 | 117480.0 | 169730.0 | 304635.0 | 78786.50 | 235410.0 |
Kraków | 179688.02 | 53160.0 | 14973.01 | 9168.39 | 87132.0 | 86355.0 | 170292.0 | 38929.80 | 168150.0 |
Poznań | 308679.42 | 64732.5 | 22494.53 | 18007.11 | 116500.0 | 127545.0 | 236946.0 | 51855.57 | 234820.0 |
Radom | 149690.02 | 40125.0 | 11578.79 | 8103.15 | 46508.0 | 63460.0 | 134412.0 | 30749.16 | 115640.0 |
Warszawa | 397923.47 | 110715.0 | 27268.49 | 22850.19 | 152192.0 | 187925.0 | 351417.0 | 101331.10 | 275530.0 |
Łódź | 215235.65 | 64807.5 | 16679.06 | 14386.68 | 78196.0 | 85040.0 | 169257.0 | 46632.04 | 174050.0 |
W każdym z tych parametrów można przekazać listę.
sprzedaz.pivot_table(index=['miasto', 'sklep'], columns=['kategoria', 'towar'], aggfunc='sum', values='wartosc')
kategoria | meble | szkolno-biurowe | wyposażenie szkolne | |||||||
---|---|---|---|---|---|---|---|---|---|---|
towar | biurko | krzesło obrotowe | dziurkacz | długopis | flamaster | plastelina | gąbka | kreda | tablica | |
miasto | sklep | |||||||||
Białystok | Pietrasiuk | 39747.35 | 27324.0 | 9285.0 | 2930.83 | 2302.74 | 7911.54 | 12600.0 | 14655.0 | 42480.0 |
Podsiadło | 39597.36 | 35121.0 | 9060.0 | 2451.05 | 2022.57 | 8542.43 | 10324.0 | 16190.0 | 46020.0 | |
Gdańsk | Krupa | 62245.85 | 73347.0 | 23145.0 | 2600.05 | 3932.28 | 15003.82 | 25316.0 | 31675.0 | 38350.0 |
Skiba | 80994.60 | 77073.0 | 16657.5 | 5139.01 | 4852.98 | 19482.84 | 23696.0 | 34550.0 | 59590.0 | |
Socha | 67945.47 | 71898.0 | 16755.0 | 6950.85 | 4904.46 | 12279.93 | 20156.0 | 40905.0 | 59000.0 | |
Żurek | 80694.62 | 59202.0 | 13380.0 | 5754.38 | 4280.76 | 12767.30 | 19956.0 | 34205.0 | 54870.0 | |
Katowice | Gaińska | 120291.98 | 91908.0 | 43207.5 | 8935.53 | 6945.84 | 28841.54 | 45304.0 | 62925.0 | 98530.0 |
Jankowski | 160489.30 | 114264.0 | 35625.0 | 9002.58 | 9048.60 | 25788.75 | 40376.0 | 61725.0 | 59590.0 | |
Michalak | 110692.62 | 98463.0 | 32992.5 | 7192.23 | 5850.90 | 24156.21 | 31800.0 | 45080.0 | 77290.0 | |
Kraków | Dudek | 48296.78 | 43815.0 | 17685.0 | 4708.40 | 2214.63 | 10841.74 | 15672.0 | 18185.0 | 40710.0 |
Kozłowski | 50396.64 | 37674.0 | 15420.0 | 2863.78 | 2285.91 | 8751.73 | 20096.0 | 28235.0 | 40710.0 | |
Sikorski | 40647.29 | 40503.0 | 8467.5 | 4076.64 | 2692.80 | 8919.17 | 21212.0 | 22700.0 | 54280.0 | |
Wróbel | 40347.31 | 48300.0 | 11587.5 | 3324.19 | 1975.05 | 10417.16 | 30152.0 | 17235.0 | 32450.0 | |
Poznań | Borowik | 118492.10 | 73899.0 | 16447.5 | 8606.24 | 4027.32 | 12447.37 | 39232.0 | 45550.0 | 67850.0 |
Romanowski | 97343.51 | 81006.0 | 27555.0 | 8348.47 | 6698.34 | 17440.67 | 28804.0 | 43205.0 | 76110.0 | |
Szewczyk | 92843.81 | 82041.0 | 20730.0 | 5539.82 | 7281.45 | 21967.53 | 48464.0 | 38790.0 | 90860.0 | |
Radom | Arendt | 34197.72 | 36294.0 | 5602.5 | 3476.17 | 1548.36 | 8509.54 | 12808.0 | 13165.0 | 40710.0 |
Czarnecki | 34197.72 | 27048.0 | 12742.5 | 2738.62 | 2123.55 | 8437.78 | 9416.0 | 19510.0 | 28320.0 | |
Grycuk | 46496.90 | 37881.0 | 11130.0 | 3368.89 | 2178.00 | 6314.88 | 12516.0 | 14625.0 | 17700.0 | |
Zawadzki | 34797.68 | 33189.0 | 10650.0 | 1995.11 | 2253.24 | 7486.96 | 11768.0 | 16160.0 | 28910.0 | |
Warszawa | Malinowski | 178788.08 | 190233.0 | 63262.5 | 13030.05 | 11925.54 | 49657.92 | 80804.0 | 84350.0 | 133930.0 |
Stefaniak | 219135.39 | 161184.0 | 47452.5 | 14238.44 | 10924.65 | 51673.18 | 71388.0 | 103575.0 | 141600.0 | |
Łódź | Kaczmarek | 76494.90 | 53406.0 | 24480.0 | 5442.97 | 4331.25 | 15234.05 | 26328.0 | 26460.0 | 62540.0 |
Kaczmarski | 73195.12 | 64998.0 | 17512.5 | 3884.43 | 4907.43 | 18209.10 | 26980.0 | 29050.0 | 53690.0 | |
Wdowiak | 65545.63 | 50853.0 | 22815.0 | 7351.66 | 5148.00 | 13188.89 | 24888.0 | 29530.0 | 57820.0 |
sprzedaz.pivot_table(index=['miasto', 'sklep'], columns=['kategoria', 'towar'], aggfunc='sum', values='wartosc', margins=True)
kategoria | meble | szkolno-biurowe | wyposażenie szkolne | All | |||||||
---|---|---|---|---|---|---|---|---|---|---|---|
towar | biurko | krzesło obrotowe | dziurkacz | długopis | flamaster | plastelina | gąbka | kreda | tablica | ||
miasto | sklep | ||||||||||
Białystok | Pietrasiuk | 39747.35 | 27324.0 | 9285.0 | 2930.83 | 2302.74 | 7911.54 | 12600.0 | 14655.0 | 42480.0 | 159236.46 |
Podsiadło | 39597.36 | 35121.0 | 9060.0 | 2451.05 | 2022.57 | 8542.43 | 10324.0 | 16190.0 | 46020.0 | 169328.41 | |
Gdańsk | Krupa | 62245.85 | 73347.0 | 23145.0 | 2600.05 | 3932.28 | 15003.82 | 25316.0 | 31675.0 | 38350.0 | 275615.00 |
Skiba | 80994.60 | 77073.0 | 16657.5 | 5139.01 | 4852.98 | 19482.84 | 23696.0 | 34550.0 | 59590.0 | 322035.93 | |
Socha | 67945.47 | 71898.0 | 16755.0 | 6950.85 | 4904.46 | 12279.93 | 20156.0 | 40905.0 | 59000.0 | 300794.71 | |
Żurek | 80694.62 | 59202.0 | 13380.0 | 5754.38 | 4280.76 | 12767.30 | 19956.0 | 34205.0 | 54870.0 | 285110.06 | |
Katowice | Gaińska | 120291.98 | 91908.0 | 43207.5 | 8935.53 | 6945.84 | 28841.54 | 45304.0 | 62925.0 | 98530.0 | 506889.39 |
Jankowski | 160489.30 | 114264.0 | 35625.0 | 9002.58 | 9048.60 | 25788.75 | 40376.0 | 61725.0 | 59590.0 | 515909.23 | |
Michalak | 110692.62 | 98463.0 | 32992.5 | 7192.23 | 5850.90 | 24156.21 | 31800.0 | 45080.0 | 77290.0 | 433517.46 | |
Kraków | Dudek | 48296.78 | 43815.0 | 17685.0 | 4708.40 | 2214.63 | 10841.74 | 15672.0 | 18185.0 | 40710.0 | 202128.55 |
Kozłowski | 50396.64 | 37674.0 | 15420.0 | 2863.78 | 2285.91 | 8751.73 | 20096.0 | 28235.0 | 40710.0 | 206433.06 | |
Sikorski | 40647.29 | 40503.0 | 8467.5 | 4076.64 | 2692.80 | 8919.17 | 21212.0 | 22700.0 | 54280.0 | 203498.40 | |
Wróbel | 40347.31 | 48300.0 | 11587.5 | 3324.19 | 1975.05 | 10417.16 | 30152.0 | 17235.0 | 32450.0 | 195788.21 | |
Poznań | Borowik | 118492.10 | 73899.0 | 16447.5 | 8606.24 | 4027.32 | 12447.37 | 39232.0 | 45550.0 | 67850.0 | 386551.53 |
Romanowski | 97343.51 | 81006.0 | 27555.0 | 8348.47 | 6698.34 | 17440.67 | 28804.0 | 43205.0 | 76110.0 | 386510.99 | |
Szewczyk | 92843.81 | 82041.0 | 20730.0 | 5539.82 | 7281.45 | 21967.53 | 48464.0 | 38790.0 | 90860.0 | 408517.61 | |
Radom | Arendt | 34197.72 | 36294.0 | 5602.5 | 3476.17 | 1548.36 | 8509.54 | 12808.0 | 13165.0 | 40710.0 | 156311.29 |
Czarnecki | 34197.72 | 27048.0 | 12742.5 | 2738.62 | 2123.55 | 8437.78 | 9416.0 | 19510.0 | 28320.0 | 144534.17 | |
Grycuk | 46496.90 | 37881.0 | 11130.0 | 3368.89 | 2178.00 | 6314.88 | 12516.0 | 14625.0 | 17700.0 | 152210.67 | |
Zawadzki | 34797.68 | 33189.0 | 10650.0 | 1995.11 | 2253.24 | 7486.96 | 11768.0 | 16160.0 | 28910.0 | 147209.99 | |
Warszawa | Malinowski | 178788.08 | 190233.0 | 63262.5 | 13030.05 | 11925.54 | 49657.92 | 80804.0 | 84350.0 | 133930.0 | 805981.09 |
Stefaniak | 219135.39 | 161184.0 | 47452.5 | 14238.44 | 10924.65 | 51673.18 | 71388.0 | 103575.0 | 141600.0 | 821171.16 | |
Łódź | Kaczmarek | 76494.90 | 53406.0 | 24480.0 | 5442.97 | 4331.25 | 15234.05 | 26328.0 | 26460.0 | 62540.0 | 294717.17 |
Kaczmarski | 73195.12 | 64998.0 | 17512.5 | 3884.43 | 4907.43 | 18209.10 | 26980.0 | 29050.0 | 53690.0 | 292426.58 | |
Wdowiak | 65545.63 | 50853.0 | 22815.0 | 7351.66 | 5148.00 | 13188.89 | 24888.0 | 29530.0 | 57820.0 | 277140.18 | |
All | 2013915.73 | 1710924.0 | 533647.5 | 143950.39 | 116656.65 | 424272.03 | 710056.0 | 892235.0 | 1503910.0 | 8049567.30 |
Zapisanie wyników do pliku¶
Zapis do Excela
wyniki = sprzedaz.pivot_table(index=['miasto', 'sklep'], columns=['kategoria', 'towar'], aggfunc='sum', values='wartosc', margins=True)
wyniki.to_excel('pivot.xlsx')
Zapis do CSV z opcjami domyślnymi
wyniki.to_csv('pivot1.csv')
Zapis do CSV z opcjami właściwymi dla Excela po polsku:
wyniki.to_csv('pivot2.csv', sep=';', decimal=',', encoding='windows-1250')
Wykresy¶
emps.salary.plot()
<Axes: xlabel='employee_id'>
emps.groupby('city').salary.mean().plot(kind='bar')
<Axes: xlabel='city'>
emps.groupby('city').salary.mean().plot(kind='bar', color=['red', 'green', 'blue'], rot=45, grid=True)
<Axes: xlabel='city'>
emps.groupby('department_name').salary.sum().plot(kind='pie')
<Axes: ylabel='salary'>