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.

In [1]:
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.

In [2]:
# to wczytuje dane w podstawowy sposób
# emps = pd.read_csv('pliki/emps.csv', sep=';')
In [3]:
# teraz dodamy kolejne ustawienia:
emps = pd.read_csv('pliki/emps.csv', sep=';', index_col='employee_id', parse_dates=['hire_date'])
In [4]:
emps
Out[4]:
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...

In [5]:
sprzedaz = pd.read_csv('pliki/sprzedaz.csv', sep=',', parse_dates=['data'])
In [6]:
sprzedaz
Out[6]:
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.

In [7]:
type(emps)
Out[7]:
pandas.core.frame.DataFrame

Pojedyncza kolumna, „seria danych” jest typu Series.

In [8]:
type(emps.last_name)
Out[8]:
pandas.core.series.Series

Jakie typu są kolumny?

In [9]:
sprzedaz.dtypes
Out[9]:
data         datetime64[ns]
miasto               object
sklep                object
kategoria            object
towar                object
cena                float64
sztuk                 int64
dtype: object

Nazwy kolumn:

In [10]:
sprzedaz.columns
Out[10]:
Index(['data', 'miasto', 'sklep', 'kategoria', 'towar', 'cena', 'sztuk'], dtype='object')
In [11]:
sprzedaz.columns[2]
Out[11]:
'sklep'
In [12]:
emps.shape
Out[12]:
(107, 10)
In [13]:
emps.size
Out[13]:
1070
In [14]:
len(emps)
Out[14]:
107

Indeksowanie¶

czyli dostęp po współrzędnych.

  • .iloc - dostęp wg współrzędnych numerycznych, jak w numpy, numeracja od zera
  • .loc - dostęp wg wartości indeksu i nazwy kolumny
In [15]:
emps.iloc[0, 0]
Out[15]:
'Steven'
In [16]:
emps.iloc[2, 3]
Out[16]:
17000

DataFrame i Series są „mutowalne”.

In [17]:
emps.iloc[0, 3] += 1
In [18]:
emps.head(5)
Out[18]:
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
In [19]:
emps.iloc[20:30, :4]
Out[19]:
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

In [20]:
emps.loc[101, 'last_name']
Out[20]:
'Kochhar'
In [21]:
emps.loc[102:105, 'first_name':'salary']
Out[21]:
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
In [22]:
emps.loc[:105, ['first_name', 'last_name', 'salary', 'city']]
Out[22]:
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:
In [23]:
emps.salary
Out[23]:
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
In [24]:
emps['hire_date']
Out[24]:
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]
In [25]:
emps[['last_name', 'hire_date']]
Out[25]:
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).

In [26]:
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

In [27]:
emps[emps.salary >= 15000]
Out[27]:
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

In [28]:
emps.salary >= 15000
Out[28]:
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
In [29]:
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.

In [30]:
emps[warunki]
Out[30]:
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 |

In [31]:
emps[(emps.job_title == 'Programmer') & (emps.salary >= 5000)]
Out[31]:
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

Funkcje argegujące¶

Statystyki itp.

Najłatwiej wywołać funkcję na pojedynczej kolumnie:

In [32]:
emps.salary.mean()
Out[32]:
6461.691588785046
In [33]:
emps.salary.min(), emps.salary.max(), emps.salary.mean(), emps.salary.median(), emps.salary.sum(), emps.salary.count(), emps.salary.std()
Out[33]:
(2100, 24001, 6461.691588785046, 6200.0, 691401, 107, 3909.408070359112)

Łącząc technikę filtrowania z wyliczaniem statystyk, można:

In [34]:
emps[emps.job_title == 'Programmer'].salary.mean()
Out[34]:
5760.0

Ciekawostka - można też tak:

In [35]:
emps.salary[emps.job_title == 'Programmer'].mean()
Out[35]:
5760.0

Funkcje liczące kilka rzeczy jednocześnie¶

In [36]:
emps.salary.describe()
Out[36]:
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
In [37]:
emps.salary.describe(percentiles=[0.1, 0.2, 0.5])
Out[37]:
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
In [38]:
emps.salary.describe(percentiles=np.arange(0, 1, 0.1))
Out[38]:
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
In [39]:
emps.city.describe()
Out[39]:
count                     106
unique                      7
top       South San Francisco
freq                       45
Name: city, dtype: object
In [40]:
emps.city.value_counts()
Out[40]:
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ę...

In [41]:
emps.salary.agg(['min', 'mean', 'max'])
Out[41]:
min      2100.000000
mean     6461.691589
max     24001.000000
Name: salary, dtype: float64
In [42]:
emps[emps.job_title == 'Programmer'].salary.agg(['count', 'min', 'mean', 'median', 'max'])
Out[42]:
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.

In [43]:
sprzedaz['wartosc'] = sprzedaz.cena * sprzedaz.sztuk
In [44]:
sprzedaz
Out[44]:
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:¶

  1. Oblicz sumę wartości transakcji w całym pliku
In [45]:
sprzedaz.wartosc.sum()
Out[45]:
8049567.3
  1. Oblicz sumę wartości transakcji w Katowicach
In [46]:
sprzedaz[sprzedaz.miasto == 'Katowice'].wartosc.sum()
Out[46]:
1456316.08
  1. Oblicz liczbę transakcji, sumę wartości (i jeśli dasz radę sumaryczną liczbę sztuk) dotyczących towaru biurko w Katowicach
In [47]:
sprzedaz[(sprzedaz.towar == 'biurko') & (sprzedaz.miasto == 'Katowice')].wartosc.agg(['count', 'sum'])
Out[47]:
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.

In [48]:
sprzedaz[(sprzedaz.towar == 'biurko') & (sprzedaz.miasto == 'Katowice')].agg({'sztuk': ['sum'], 'wartosc': ['count', 'sum']})
Out[48]:
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:

In [49]:
emps.groupby('job_title').salary.mean()
Out[49]:
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:

In [50]:
emps.groupby('job_title').salary.agg(['count', 'min', 'median', 'max'])
Out[50]:
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:

In [51]:
emps.groupby('job_title').agg({'salary': ['min', 'mean', 'max'], 'hire_date': ['min', 'max']})
Out[51]:
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ż

In [52]:
sprzedaz.groupby(['miasto', 'towar']).wartosc.sum()
Out[52]:
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
In [53]:
sprzedaz.groupby(['miasto', 'towar']).agg({'wartosc': 'sum'})
Out[53]:
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.

In [54]:
sprzedaz.pivot_table(index='miasto', columns='towar', aggfunc='sum', values='wartosc')
Out[54]:
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ę.

In [55]:
sprzedaz.pivot_table(index=['miasto', 'sklep'], columns=['kategoria', 'towar'], aggfunc='sum', values='wartosc')
Out[55]:
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
In [56]:
sprzedaz.pivot_table(index=['miasto', 'sklep'], columns=['kategoria', 'towar'], aggfunc='sum', values='wartosc', margins=True)
Out[56]:
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

In [57]:
wyniki = sprzedaz.pivot_table(index=['miasto', 'sklep'], columns=['kategoria', 'towar'], aggfunc='sum', values='wartosc', margins=True)
In [58]:
wyniki.to_excel('pivot.xlsx')

Zapis do CSV z opcjami domyślnymi

In [59]:
wyniki.to_csv('pivot1.csv')

Zapis do CSV z opcjami właściwymi dla Excela po polsku:

In [60]:
wyniki.to_csv('pivot2.csv', sep=';', decimal=',', encoding='windows-1250')

Wykresy¶

In [61]:
emps.salary.plot()
Out[61]:
<Axes: xlabel='employee_id'>
No description has been provided for this image
In [62]:
emps.groupby('city').salary.mean().plot(kind='bar')
Out[62]:
<Axes: xlabel='city'>
No description has been provided for this image
In [63]:
emps.groupby('city').salary.mean().plot(kind='bar', color=['red', 'green', 'blue'], rot=45, grid=True)
Out[63]:
<Axes: xlabel='city'>
No description has been provided for this image
In [64]:
emps.groupby('department_name').salary.sum().plot(kind='pie')
Out[64]:
<Axes: ylabel='salary'>
No description has been provided for this image
In [ ]: