Przetwarzanie i analiza danych w środowisku Python

Author

p.zamaro@aotm.gov.pl

Published

December 5, 2023

1. Wprowadzenie

Quarto enables you to weave together content and executable code into a finished document. To learn more about Quarto see https://quarto.org.


2. Podstawy Pythona

  • Zakres: Typy danych, składnia, instalacja pakietów, podstawowe funkcje.

  • Kompetencje: Zrozumienie typów danych i składni pythona, umiejętność pisania prostego kodu.

Typy zmiennych

  • Lista (list) jest podobna do listy w R (list()). Oba są kolekcjami, które mogą przechowywać różne typy danych.

  • Słownik (dict) można porównać do list w R z nazwanymi elementami lub wektorów. W R nie ma bezpośredniego odpowiednika dla słownika, ale listy lub wektory z nazwami elementów pełnią podobną rolę.

  • Krotka w Pythonie (tuple) jest niezmienialną sekwencją, dla której nie ma bezpośredniego odpowiednika w R.

  • Zbiór (set) jest podobny do zbioru w R (set), oba reprezentują kolekcję unikalnych elementów.

  • DataFrame (pandas.DataFrame) jest analogiczny do data.frame w R. Oba są używane do przechowywania danych tabelarycznych.

  • Seria (pandas.Series) jest podobna do wektora w R (vector). Obie reprezentują jednowymiarowe sekwencje danych.

Nazwa zmiennej Typ zmiennej Nazwa w R
lista list list()
słownik dict list() lub vector
krotka tuple -
zbiór set set
dataframe pandas.DataFrame data.frame
seria pandas.Series vector

Składnia

Składnia języka Python różni się od składni R w kilku kluczowych aspektach, co ma wpływ na sposób pisania i czytania kodu.

Wcięcia vs Nawiasy Klamrowe

Python używa wcięć (spacji lub tabulatorów) do definiowania bloków kodu. Wcięcia są kluczowe dla struktury kodu i muszą być konsekwentne. Przykład:

Col1 Col2 Col3
Wcięcia vs Nawiasy Klamrowe Python używa wcięć do definiowania bloków kodu. R używa nawiasów klamrowych {} do definiowania bloków kodu, podobnie jak wiele innych języków programowania.
if x > 10:
    print("x jest większe niż 10")
Indeksowanie Python rozpoczyna indeksowanie od 0. Przykład: lista[0] oznacza pierwszy element listy. R rozpoczyna indeksowanie od 1. Przykład: lista[1] oznacza pierwszy element listy.
Przypisanie Zmiennych Python używa operatora = do przypisania wartości do zmiennej. Przykład: x = 5 R często używa <- jako operatora przypisania, chociaż = jest również akceptowany. Przykład: x <- 5 lub x = 5
Definicja Funkcji Funkcje definiuje się za pomocą słowa kluczowego def, a następnie nazwy funkcji i argumentów w nawiasach. W R funkcje definiuje się za pomocą function, a argumenty umieszcza się w nawiasach.
def moja_funkcja(x):
    return x * 2
moja_funkcja <- function(x) {

  x * 2
}
    if x > 10:
        print("x jest większe niż 10")

R używa nawiasów klamrowych {} do definiowania bloków kodu, podobnie jak wiele innych języków programowania. Przykład:

```{r eval = F}

if (x > 10) { print(“x jest większe niż 10”) }




2.  **Indeksowanie** Python rozpoczyna indeksowanie od 0. Przykład: lista\[0\] oznacza pierwszy element listy. R rozpoczyna indeksowanie od 1. Przykład: lista\[1\] oznacza pierwszy element listy.

3.  **Przypisanie Zmiennych**

Python używa operatora = do przypisania wartości do zmiennej. Przykład: x = 5 R często używa \<- jako operatora przypisania, chociaż = jest również akceptowany. Przykład: x \<- 5 lub x = 5

4.  **Definicja Funkcji**



```{def moja_funkcja(x):}
        return x * 2

W R funkcje definiuje się za pomocą function, a argumenty umieszcza się w nawiasach. Przykład:

```{r eval = F}

moja_funkcja <- function(x) {

x * 2 }




**Biblioteki vs Pakiety**

W Pythonie, do importowania modułów/bibliotek używa się import. Można importować całe moduły lub poszczególne funkcje. Przykład: import numpy as np lub from math import sqrt

W R, aby używać pakietów, najpierw należy je załadować za pomocą library(). Przykład: library(ggplot2)

### Instalacja pakietów

-   Funkcja `import`
-   Składnia: `import nazwa_pakietu`
-   Przykład użycia:

::: {.cell execution_count=1}
``` {.python .cell-code}
import random
import pandas as pd
import plotly as px
import random

from datetime import datetime
from distutils.command import install

:::

3. Przetwarzanie danych - pakiet pandas

3.1. Tworzenie zbiorów danych

import pandas as pd
from tabulate import tabulate

random.seed(0)

start_date = datetime(2015, 1, 1).date()
end_date = datetime(2020, 12, 31).date()

def random_date(start, end):
    return start + (end - start) * random.random()

2.1 Tworzenie zmiennych

Tworzenie ramki danych

n = 100

plec = ["M", "K"]

wojewodztwa = ["mazowieckie","śląskie", "wielkopolskie", "małopolskie", 
               "dolnośląskie", "warmińsko-mazurskie", "lubuskie", "lubelskie", 
               "podlaskie", "łódzkie", "zachodniopomorskie", "pomorskie", 
               "kujawsko-pomorskie","wielkoposlkie"]

kody_icd_10 = ["I10", "E11", "J18", "K21", "L20", "M54", "N30", "O14", "P07", "R51"]

nazwy_swiadczen = ["Badanie krwi", "USG", "RTG", "EKG", "Konsultacja specjalistyczna", "Operacja"]

dane = pd.DataFrame({
    "id": range(1, n + 1),
    "wiek": [random.randint(0, 100) for _ in range(n)],
    "płeć": [random.choice(plec) for _ in range(n)],
    "województwo": [random.choice(wojewodztwa) for _ in range(n)],
    "kod ICD-10": [random.choice(kody_icd_10) for _ in range(n)],
    "data": [random_date(start_date, end_date) for _ in range(n)],
    "nazwa świadczenia": [random.choice(nazwy_swiadczen) for _ in range(n)],
    "koszt świadczenia": [round(random.uniform(100, 1000), 2) for _ in range(n)],
    "zgon": [random.choice(["tak", "nie"]) for _ in range(n)]
})

print('Początek obserwacji:', start_date)
print('Koniec obserwacji: ', end_date)
Początek obserwacji: 2015-01-01
Koniec obserwacji:  2020-12-31

Selekcja danych

Wybór kolumny

kolumna = dane['wiek']
print(kolumna.to_string(index=False))
 49
 97
 53
  5
 33
 65
 62
 51
100
 38
 61
 45
 74
 27
 64
 17
 36
 17
 96
 12
 79
 32
 68
 90
 77
 18
 39
 12
 93
  9
 87
 42
 60
 71
 12
 45
 55
 40
 78
 81
 26
 70
 61
 56
 66
 33
  7
 70
  1
 11
 92
 51
 90
100
 85
 80
  0
 78
 63
 42
 31
 93
 41
 90
  8
 24
 72
 28
 30
 18
 69
 57
 11
 10
 40
 65
 62
 13
 38
 70
 37
 90
 15
 70
 42
 69
 26
 77
 70
 75
 36
 56
 11
 76
 49
 40
 73
 30
 37
 23

Wybór wierszy

wiersze = dane[13:21]
print(wiersze.head().to_string(index=False))
 id  wiek płeć   województwo kod ICD-10       data           nazwa świadczenia  koszt świadczenia zgon
 14    27    M wielkoposlkie        J18 2016-02-25                         EKG             877.65  tak
 15    64    M       łódzkie        P07 2015-09-09                         EKG             392.05  nie
 16    17    K wielkopolskie        M54 2019-12-06                         USG             327.33  tak
 17    36    K     pomorskie        E11 2020-02-12                         EKG             417.25  nie
 18    17    K  dolnośląskie        J18 2015-03-02 Konsultacja specjalistyczna             209.24  nie

Zakres etykiet

zakres_etykieta = dane.loc[2:11, 
                          ['wiek', 'płeć']]
print(zakres_etykieta)
    wiek płeć
2     53    M
3      5    K
4     33    K
5     65    M
6     62    M
7     51    M
8    100    M
9     38    M
10    61    M
11    45    K
 zakres_pozycja = dane.iloc[10:20, [5, 7]]
print(zakres_pozycja.head())
          data  koszt świadczenia
10  2020-12-29             487.98
11  2018-07-06             475.32
12  2015-12-31             546.96
13  2016-02-25             877.65
14  2015-09-09             392.05

FILTROWANIE DANYCH

Filtrowanie wyników w DataFrame w pandas jest bardzo podobne do używania funkcji filter z pakietu dplyr w R. W pandas, możesz używać warunków logicznych bezpośrednio na DataFrame do filtrowania danych. Kluczowym aspektem jest stosowanie nawiasów do grupowania warunków oraz używanie operatorów logicznych (&, |) do łączenia tych warunków.

dane.query('wiek > 20')
dane.query('wiek > 20 & id > 56')
#dane.query('płeć' == 'M')
id wiek płeć województwo kod ICD-10 data nazwa świadczenia koszt świadczenia zgon
57 58 78 M podlaskie M54 2019-03-28 Operacja 312.99 tak
58 59 63 K lubelskie N30 2017-10-27 Badanie krwi 265.55 nie
59 60 42 M podlaskie P07 2019-10-19 Operacja 435.22 nie
60 61 31 K łódzkie J18 2018-02-05 Operacja 696.88 nie
61 62 93 M kujawsko-pomorskie L20 2020-06-28 Konsultacja specjalistyczna 874.88 tak
62 63 41 M mazowieckie E11 2015-05-26 RTG 641.09 nie
63 64 90 M mazowieckie O14 2015-10-13 USG 454.42 nie
65 66 24 K warmińsko-mazurskie I10 2019-07-21 RTG 218.82 nie
66 67 72 K dolnośląskie L20 2017-09-09 Operacja 369.45 tak
67 68 28 M wielkoposlkie J18 2020-03-03 Operacja 475.07 nie
68 69 30 M lubelskie P07 2019-10-21 Badanie krwi 933.76 nie
70 71 69 M kujawsko-pomorskie L20 2017-10-06 USG 368.23 nie
71 72 57 M wielkoposlkie N30 2017-03-24 Badanie krwi 419.11 tak
74 75 40 K małopolskie N30 2015-03-15 RTG 673.34 tak
75 76 65 K podlaskie E11 2015-07-18 USG 576.29 nie
76 77 62 K zachodniopomorskie E11 2019-10-06 EKG 438.79 tak
78 79 38 M wielkoposlkie O14 2018-08-07 Operacja 965.76 tak
79 80 70 M pomorskie O14 2015-06-17 Badanie krwi 911.14 nie
80 81 37 M wielkopolskie M54 2017-07-23 Badanie krwi 497.17 nie
81 82 90 M mazowieckie M54 2019-07-12 Badanie krwi 434.44 nie
83 84 70 K zachodniopomorskie O14 2020-05-28 RTG 181.95 tak
84 85 42 M lubuskie E11 2017-07-04 Badanie krwi 266.91 tak
85 86 69 K warmińsko-mazurskie O14 2020-10-31 Konsultacja specjalistyczna 197.75 nie
86 87 26 M mazowieckie N30 2020-01-27 Operacja 200.94 tak
87 88 77 M małopolskie I10 2020-10-31 Konsultacja specjalistyczna 644.99 nie
88 89 70 K mazowieckie L20 2018-08-23 Konsultacja specjalistyczna 238.49 tak
89 90 75 K pomorskie M54 2016-05-26 USG 732.34 tak
90 91 36 K kujawsko-pomorskie J18 2020-03-09 USG 935.44 tak
91 92 56 K mazowieckie J18 2015-02-14 Badanie krwi 266.84 nie
93 94 76 K zachodniopomorskie N30 2019-06-11 Konsultacja specjalistyczna 257.26 tak
94 95 49 M podlaskie E11 2016-10-24 Operacja 963.58 tak
95 96 40 M łódzkie E11 2018-06-03 Konsultacja specjalistyczna 406.35 nie
96 97 73 K śląskie E11 2016-12-29 EKG 571.01 tak
97 98 30 M małopolskie K21 2017-12-17 Konsultacja specjalistyczna 419.83 tak
98 99 37 K śląskie K21 2016-07-28 RTG 668.37 nie
99 100 23 M łódzkie I10 2019-12-13 Badanie krwi 177.85 nie

Wiele warunków

wynik = dane[dane['wiek'] > 30]

Funkcja query

# AND - oba warunki muszą być spełnione
wynik = dane[(dane['wiek'] > 30) & (dane['płeć'] == 'K')]

# OR - wystarczy, że jeden z warunków jest spełniony
wynik = dane[(dane['wiek'] > 30) | (dane['płeć'] == 'K')]

Listy wartości

# Załóżmy, że chcesz wybrać wiersze, gdzie kolumna 'województwo' zawiera jedno z kilku województw
województwa = ['pomorskie', 'małopolskie', 'śląskie']
wynik = dane[dane['województwo'].isin(województwa)]

GRUPOWANIE DANYCH

groupby

grupuj = pd.DataFrame(dane.groupby('płeć'))
print(grupuj)
 
ow = dane.groupby('województwo')
print(pd.DataFrame(ow))
   0                                                  1
0  K      id  wiek płeć          województwo kod ICD...
1  M       id  wiek płeć          województwo kod IC...
                      0                                                  1
0          dolnośląskie      id  wiek płeć   województwo kod ICD-10    ...
1    kujawsko-pomorskie      id  wiek płeć         województwo kod ICD-...
2             lubelskie      id  wiek płeć województwo kod ICD-10      ...
3              lubuskie      id  wiek płeć województwo kod ICD-10      ...
4           mazowieckie      id  wiek płeć  województwo kod ICD-10     ...
5           małopolskie      id  wiek płeć  województwo kod ICD-10     ...
6             podlaskie      id  wiek płeć województwo kod ICD-10      ...
7             pomorskie      id  wiek płeć województwo kod ICD-10      ...
8   warmińsko-mazurskie      id  wiek płeć          województwo kod ICD...
9         wielkopolskie      id  wiek płeć    województwo kod ICD-10   ...
10        wielkoposlkie      id  wiek płeć    województwo kod ICD-10   ...
11   zachodniopomorskie      id  wiek płeć         województwo kod ICD-...
12              łódzkie       id  wiek płeć województwo kod ICD-10     ...
13              śląskie      id  wiek płeć województwo kod ICD-10      ...

Agregacje

# Dla jednej kolumny
dane['wiek'].agg('mean')


# Wiele kolumn
dane.agg({
  'wiek': 'mean', 
  'koszt świadczenia': 'max'
  })


#Agregacja po grupowaniu
dane.groupby('płeć').agg({
  'wiek': 'mean', 
  'koszt świadczenia': 'max'
  })


#Agregacja właśną funkcją
def zakres_wiekowy(x):
    return max(x) - min(x)
wynik = dane.agg({'wiek': zakres_wiekowy})

DataFrame.sum - Return the sum over DataFrame axis.

DataFrame.cummax - Return cumulative maximum over DataFrame axis.

DataFrame.cummin - Return cumulative minimum over DataFrame axis.

DataFrame.cumsum - Return cumulative sum over DataFrame axis.

DataFrame.cumprod - Return cumulative product over a DataFrame or Series axis.

size

# Tabele grupujące
 
a = pd.DataFrame(dane.groupby('województwo'))
 
# Wczytywanie danych
# wczytaj = pd.read_csv('dane_pythossn.csv')
# print(wczytaj)
# Zapisywanie danych
# dane.to_excel('dane_python.xlsx')
# dane.to_csv('dane_pythona.xlsx', sep=',')

Tworzenie nowych kolumn

Przegląd danych

Pierwsze 5 wierszy

print(dane.head().to_markdown(index=False))
|   id |   wiek | płeć   | województwo        | kod ICD-10   | data       | nazwa świadczenia   |   koszt świadczenia | zgon   |
|-----:|-------:|:-------|:-------------------|:-------------|:-----------|:--------------------|--------------------:|:-------|
|    1 |     49 | M      | podlaskie          | K21          | 2017-04-23 | EKG                 |              231.12 | tak    |
|    2 |     97 | M      | dolnośląskie       | L20          | 2015-08-03 | EKG                 |              902.66 | nie    |
|    3 |     53 | M      | wielkopolskie      | L20          | 2018-05-04 | EKG                 |              479.85 | tak    |
|    4 |      5 | K      | małopolskie        | J18          | 2016-09-26 | Badanie krwi        |              175.63 | nie    |
|    5 |     33 | K      | kujawsko-pomorskie | E11          | 2020-07-09 | USG                 |              194.29 | nie    |

Ostatnie 5 wierszy

print("Ostatnie 5 wierszy: \n",   
      tabulate(
          dane.tail()))
Ostatnie 5 wierszy: 
 --  ---  --  -  -----------  ---  ----------  ---------------------------  ------  ---
95   96  40  M  łódzkie      E11  2018-06-03  Konsultacja specjalistyczna  406.35  nie
96   97  73  K  śląskie      E11  2016-12-29  EKG                          571.01  tak
97   98  30  M  małopolskie  K21  2017-12-17  Konsultacja specjalistyczna  419.83  tak
98   99  37  K  śląskie      K21  2016-07-28  RTG                          668.37  nie
99  100  23  M  łódzkie      I10  2019-12-13  Badanie krwi                 177.85  nie
--  ---  --  -  -----------  ---  ----------  ---------------------------  ------  ---

Podsumowanie zbioru

print("Podsumowanie zbioru", 
      dane.info())   
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 100 entries, 0 to 99
Data columns (total 9 columns):
 #   Column             Non-Null Count  Dtype  
---  ------             --------------  -----  
 0   id                 100 non-null    int64  
 1   wiek               100 non-null    int64  
 2   płeć               100 non-null    object 
 3   województwo        100 non-null    object 
 4   kod ICD-10         100 non-null    object 
 5   data               100 non-null    object 
 6   nazwa świadczenia  100 non-null    object 
 7   koszt świadczenia  100 non-null    float64
 8   zgon               100 non-null    object 
dtypes: float64(1), int64(2), object(6)
memory usage: 7.2+ KB
Podsumowanie zbioru None

Statystyki opisowe

print("Statystyki opisowe:\n",
      dane.describe().to_markdown(index=False))
Statystyki opisowe:
 |       id |    wiek |   koszt świadczenia |
|---------:|--------:|--------------------:|
| 100      | 100     |             100     |
|  50.5    |  50.44  |             496.365 |
|  29.0115 |  27.461 |             249.534 |
|   1      |   0     |             102.91  |
|  25.75   |  29.5   |             282.21  |
|  50.5    |  51     |             438.86  |
|  75.25   |  71.25  |             678.285 |
| 100      | 100     |             965.76  |

Porównanie funkci R i Python

Opis funkcji Python R
Instalacja pakietów import nazwa_pakietu library(nazwa_pakietu)
Ramki danych data.frame(dane) Data.Frame(dane)
Tabele html tabulate(dataframe) kable(dataframe)
Podsumowanie zbioru dane.info( str(dane)
Ramki danych dane.head() head(dane)
Tabele html dane.describe() summary(dane)

Tworzenie tabel

tabulate

from tabulate import tabulate

print(tabulate(dane.head(), 
               headers='keys', 
               tablefmt='pipe', 
               showindex=False))
|   id |   wiek | płeć   | województwo        | kod ICD-10   | data       | nazwa świadczenia   |   koszt świadczenia | zgon   |
|-----:|-------:|:-------|:-------------------|:-------------|:-----------|:--------------------|--------------------:|:-------|
|    1 |     49 | M      | podlaskie          | K21          | 2017-04-23 | EKG                 |              231.12 | tak    |
|    2 |     97 | M      | dolnośląskie       | L20          | 2015-08-03 | EKG                 |              902.66 | nie    |
|    3 |     53 | M      | wielkopolskie      | L20          | 2018-05-04 | EKG                 |              479.85 | tak    |
|    4 |      5 | K      | małopolskie        | J18          | 2016-09-26 | Badanie krwi        |              175.63 | nie    |
|    5 |     33 | K      | kujawsko-pomorskie | E11          | 2020-07-09 | USG                 |              194.29 | nie    |

markdown

print(dane.head().to_markdown(index = False))
|   id |   wiek | płeć   | województwo        | kod ICD-10   | data       | nazwa świadczenia   |   koszt świadczenia | zgon   |
|-----:|-------:|:-------|:-------------------|:-------------|:-----------|:--------------------|--------------------:|:-------|
|    1 |     49 | M      | podlaskie          | K21          | 2017-04-23 | EKG                 |              231.12 | tak    |
|    2 |     97 | M      | dolnośląskie       | L20          | 2015-08-03 | EKG                 |              902.66 | nie    |
|    3 |     53 | M      | wielkopolskie      | L20          | 2018-05-04 | EKG                 |              479.85 | tak    |
|    4 |      5 | K      | małopolskie        | J18          | 2016-09-26 | Badanie krwi        |              175.63 | nie    |
|    5 |     33 | K      | kujawsko-pomorskie | E11          | 2020-07-09 | USG                 |              194.29 | nie    |
import pandas as pd