Python2019/labs04/Pandas.ipynb
2019-02-09 08:54:43 +01:00

53 KiB

Podstawy Analizy danych w Pythonie: pandas

9 lutego 2019

Ostatnia cześć kursu Pythona będzie dotyczyć biblioteki pandas, która służy do analizy danych. Zacznijmy zatem od importu. Przeważnie bibliotekę skraca się do _pd:

%matplotlib inline
import sys
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd

Pandas posiada dwie podstawowe struktury danych:

  • szereg (Series),

  • ramka danych (DataFrame).

    Zaczniemy od szeregów. Szereg danych, mówiąc prościej jest to lista danych tego samego typu.

Żeby zobaczyć szeregi w akcji, stwórzmy listę losowych liczb:

losowe = np.random.randint(1, 20, 26)
print(losowe)
[ 4  5 10  9 13  7  7  4 19 13 13 10  2  3 17 18  3 14  4 19  5  6  9  5
 13 14]

A następnie stwórzmy szereg, korzystając z powyższych liczb:

dane = pd.Series(losowe)
print(dane)
0      4
1      5
2     10
3      9
4     13
5      7
6      7
7      4
8     19
9     13
10    13
11    10
12     2
13     3
14    17
15    18
16     3
17    14
18     4
19    19
20     5
21     6
22     9
23     5
24    13
25    14
dtype: int64

Czym różni się szereg od listy? Szereg danych posiada indeks, czyli klucz, dzięki ktoremu możemy zindetyfikować dane. Domyślnie, indeks jest ciągiem liczb zaczynających się od zera. Nie musi tak być, możemy podczas tworzenia przekazać również indeks:

dane2 = pd.Series([1,2,3,4,5], index=['a', 'b', 'c', 'd', 'e'])
print(dane2)
a    1
b    2
c    3
d    4
e    5
dtype: int64

Jak można domyśleć się, indeks służy nam do uzyskania dostępu do danego elementu:

print(dane2['b'])
2

Więcej o dostępnie do danych będzie w dalszej części kursu.

Żeby uzyskać rozmiar danych możemy wykorzystać znaną już funkcję len lub wykorzystać polę shape.

print(len(dane))
print(dane.shape)
26
(26,)

Przeważnie zbiory danych, na których pracujemy są duże. Stąd, próba ich wyświetlenia może okazać się karkołomna lub nawet niemożliwa. Czasem chcemy tylko zobaczyć pogląd. Do tego służą dwie metody: head i tail, które zwrócą nam kilka pierwszych lub ostatnich wierszy z szeregu:

print(dane.head())
0     4
1     5
2    10
3     9
4    13
dtype: int64
print(dane.tail())
21     6
22     9
23     5
24    13
25    14
dtype: int64

Szeregi są dostosowane do analizy danych. Np. udostępniają prosty sposób do uzyskania podstawowych statystyk:

print("Średnia:", dane.mean())
print("Mediana:", dane.median())
Średnia: 9.461538461538462
Mediana: 9.0

Jak i inne przydatne funkcje:

print("Zbiór wartości:", dane.unique())
print("Zliczanie", dane.value_counts())
Zbiór wartości: [14  6 16  7 17 13 15  2 12  3  4  1  9 19  5]
Zliczanie 15    4
13    3
4     3
12    2
7     2
2     2
19    1
17    1
16    1
14    1
9     1
6     1
5     1
3     1
1     1
dtype: int64

Metoda value_counts zwraca nam szereg danych, który możemy wykorzystać do dalszych badań. Na przyklad, żeby wyświetlić 5 najczęściej występujących wartości, możemy napisać:

print(dane.value_counts().head())
15    4
13    3
4     3
12    2
7     2
dtype: int64

Żeby uzyskać wszystkie podstawowe statystyki, możmey wywołać metodę describe:

print(dane.describe())
count    25.000000
mean      9.720000
std       5.556678
min       1.000000
25%       4.000000
50%      12.000000
75%      15.000000
max      19.000000
dtype: float64

A żeby wyświetlić je w postaci wykresu:

dane.hist()
<matplotlib.axes._subplots.AxesSubplot at 0x7f28547b2f98>

(Dane zostały wygenerowane w sposób losowy, stąd ich analiza jak na razie jest pozbawiona sensu.)

Indeksowanie, czyli dostęp do danych

Stwórzmy szereg danych, którego indeks będzie składać się z wielkich liter alfabetu:

import string
litery = list(string.ascii_uppercase)
dane3 = pd.Series(losowe, index=litery)
print(dane3.head())
A    11
B    13
C     6
D     9
E    18
dtype: int64

Najprostszym sposobem dostępu do danych jest przez indeks:

print(dane3['E'])
18

Szeregi udostępniają wiele więcej. Jeżeli chcemy zobaczyć przykłady o kluczach _P, Y, T, to możemy podać listę indeksów jako argument:

print(dane3[['P', 'Y', 'T']])
P    12
Y     9
T     7
dtype: int64

Możemy również podać zakres danych:

print(dane3['B':'E'])
B    13
C     6
D     9
E    18
dtype: int64

Jeżeli zmienimy indeks szeregu, to cay czas mamy możliwość pracy na indeskach liczbowych:

print(dane3[2:5])
C     6
D     9
E    18
dtype: int64

Mapowanie

Szeregi pozwalają zmieniać dane, które przechowują. Pojedyńcze wartości mozemy zmieniać przy pomocy odwołania się do konkretnego elementu:

dane3[2] = 777
print(dane3[2])
777

Jeżeli chcemy zmienić cały szereg przy pomocy funkcji, możemy wykorzystać metodę map:

def cube(x):
    return x ** 3
print(dane3.map(cube))
A         1331
B         2197
C    469097433
D          729
E         5832
F         1000
G          343
H          512
I          125
J            8
K         3375
L         4096
M          216
N         5832
O          343
P         1728
Q         4913
R         1728
S         2197
T          343
U         4913
V         3375
W         2744
X         1331
Y          729
Z         4096
dtype: int64

_Uwaga: w Pythonie istnieją funkcje lambda, które można tu wykorzystać.

Ramki danych

Ramka danych jest odpowiednikiem tabeli znanej z R lub sqla. Patrząc z innego punktu widzenia, jest lista szeregóœ danych, które są połącząne z sobą wspólnym indeksem. Stwórzmy ramkę danych składających się z małych i wielkich liter:

wielkie = list(string.ascii_uppercase)
male = list(string.ascii_lowercase)
surowe = list(zip(male, wielkie))
print(surowe)

dane = pd.DataFrame(surowe)
print(dane)
[('a', 'A'), ('b', 'B'), ('c', 'C'), ('d', 'D'), ('e', 'E'), ('f', 'F'), ('g', 'G'), ('h', 'H'), ('i', 'I'), ('j', 'J'), ('k', 'K'), ('l', 'L'), ('m', 'M'), ('n', 'N'), ('o', 'O'), ('p', 'P'), ('q', 'Q'), ('r', 'R'), ('s', 'S'), ('t', 'T'), ('u', 'U'), ('v', 'V'), ('w', 'W'), ('x', 'X'), ('y', 'Y'), ('z', 'Z')]
    0  1
0   a  A
1   b  B
2   c  C
3   d  D
4   e  E
5   f  F
6   g  G
7   h  H
8   i  I
9   j  J
10  k  K
11  l  L
12  m  M
13  n  N
14  o  O
15  p  P
16  q  Q
17  r  R
18  s  S
19  t  T
20  u  U
21  v  V
22  w  W
23  x  X
24  y  Y
25  z  Z

Jak widzimy, ramkę danych tworzymy podając listę przykładów. W powyższej ramce mamy dwie kolumny nazwane _0 i 1. Zmieńmy te nazwy na bardziej czytelne:

dane.columns = ["małe", "wielkie"]
print(dane.head())
  małe wielkie
0    a       A
1    b       B
2    c       C
3    d       D
4    e       E

Obsługa ramki danych nie różni się za bardzo od obsługi szeregu, np. działaja metody head i tail, jak i inne:

print(dane.max())
print(dane.describe())
małe       z
wielkie    Z
dtype: object
       małe wielkie
count    26      26
unique   26      26
top       j       M
freq      1       1

Dodajmy trzecią kolumnę składającą się z losowych liczb:

dane['losowe'] = np.random.randint(1, 20, 26)
df = pd.read_csv("./titanic_train.tsv", sep='\t', index_col='PassengerId')
print(df.columns)
Index(['Survived', 'Pclass', 'Name', 'Sex', 'Age', 'SibSp', 'Parch', 'Ticket',
       'Fare', 'Cabin', 'Embarked'],
      dtype='object')
df.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 891 entries, 1 to 891
Data columns (total 11 columns):
Survived    891 non-null int64
Pclass      891 non-null int64
Name        891 non-null object
Sex         891 non-null object
Age         714 non-null float64
SibSp       891 non-null int64
Parch       891 non-null int64
Ticket      891 non-null object
Fare        891 non-null float64
Cabin       204 non-null object
Embarked    889 non-null object
dtypes: float64(2), int64(4), object(5)
memory usage: 83.5+ KB
df.head()
Survived Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked
PassengerId
1 0 3 Braund\t Mr. Owen Harris male 22.0 1 0 A/5 21171 7.2500 NaN S
2 1 1 Cumings\t Mrs. John Bradley (Florence Briggs T... female 38.0 1 0 PC 17599 71.2833 C85 C
3 1 3 Heikkinen\t Miss. Laina female 26.0 0 0 STON/O2. 3101282 7.9250 NaN S
4 1 1 Futrelle\t Mrs. Jacques Heath (Lily May Peel) female 35.0 1 0 113803 53.1000 C123 S
5 0 3 Allen\t Mr. William Henry male 35.0 0 0 373450 8.0500 NaN S
df[['Survived', 'Pclass']].head()
Survived Pclass
PassengerId
1 0 3
2 1 1
3 1 3
4 1 1
5 0 3
print(df.shape)
(891, 11)
df.loc[888]
Survived                                1
Pclass                                  1
Name        Graham\t Miss. Margaret Edith
Sex                                female
Age                                    19
SibSp                                   0
Parch                                   0
Ticket                             112053
Fare                                   30
Cabin                                 B42
Embarked                                S
Name: 888, dtype: object
df.loc[888:892]
Survived Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked
PassengerId
888 1 1 Graham\t Miss. Margaret Edith female 19.0 0 0 112053 30.00 B42 S
889 0 3 Johnston\t Miss. Catherine Helen "Carrie" female NaN 1 2 W./C. 6607 23.45 NaN S
890 1 1 Behr\t Mr. Karl Howell male 26.0 0 0 111369 30.00 C148 C
891 0 3 Dooley\t Mr. Patrick male 32.0 0 0 370376 7.75 NaN Q
df[df.Survived == 1].head()
Survived Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked
PassengerId
2 1 1 Cumings\t Mrs. John Bradley (Florence Briggs T... female 38.0 1 0 PC 17599 71.2833 C85 C
3 1 3 Heikkinen\t Miss. Laina female 26.0 0 0 STON/O2. 3101282 7.9250 NaN S
4 1 1 Futrelle\t Mrs. Jacques Heath (Lily May Peel) female 35.0 1 0 113803 53.1000 C123 S
9 1 3 Johnson\t Mrs. Oscar W (Elisabeth Vilhelmina B... female 27.0 0 2 347742 11.1333 NaN S
10 1 2 Nasser\t Mrs. Nicholas (Adele Achem) female 14.0 1 0 237736 30.0708 NaN C
df["FSize"] = df.SibSp + df.Parch + 1
df.FSize.head()
PassengerId
1    2
2    2
3    1
4    2
5    1
Name: FSize, dtype: int64
df[['Sex', 'Survived']].groupby('Sex').mean()
Survived
Sex
female 0.742038
male 0.188908
df[['FSize', 'Survived']].loc[df['FSize'] == 1].groupby('FSize').mean()
Survived
FSize
1 0.303538
df[['FSize', 'Survived']].groupby('FSize').mean().loc[1]
0.30353817504655495
for idx, row in df.iterrows():
    if idx < 5:
        print(row)
Survived                           0
Pclass                             3
Name        Braund\t Mr. Owen Harris
Sex                             male
Age                               22
SibSp                              1
Parch                              0
Ticket                     A/5 21171
Fare                            7.25
Cabin                            NaN
Embarked                           S
FSize                              2
Name: 1, dtype: object
Survived                                                    1
Pclass                                                      1
Name        Cumings\t Mrs. John Bradley (Florence Briggs T...
Sex                                                    female
Age                                                        38
SibSp                                                       1
Parch                                                       0
Ticket                                               PC 17599
Fare                                                  71.2833
Cabin                                                     C85
Embarked                                                    C
FSize                                                       2
Name: 2, dtype: object
Survived                          1
Pclass                            3
Name        Heikkinen\t Miss. Laina
Sex                          female
Age                              26
SibSp                             0
Parch                             0
Ticket             STON/O2. 3101282
Fare                          7.925
Cabin                           NaN
Embarked                          S
FSize                             1
Name: 3, dtype: object
Survived                                                1
Pclass                                                  1
Name        Futrelle\t Mrs. Jacques Heath (Lily May Peel)
Sex                                                female
Age                                                    35
SibSp                                                   1
Parch                                                   0
Ticket                                             113803
Fare                                                 53.1
Cabin                                                C123
Embarked                                                S
FSize                                                   2
Name: 4, dtype: object