ium/IUM_02.Dane.ipynb

409 KiB
Raw Blame History

Logo 1

Inżynieria uczenia maszynowego

2. Dane [laboratoria]

Tomasz Ziętkiewicz (2023)

Logo 2

Plan na dzisiaj

  1. Motywacja
  2. Podział danych
  3. Skąd wziąć dane?
  4. Przygotowanie danych
  5. Zadanie

Motywacja

  • Zasada "Garbage in - garbage out"
  • Im lepszej jakości dane - tym lepszy model
  • Najlepsza architektura, najpotężniejsze zasoby obliczeniowe i najbardziej wyrafinowane metody nie pomogą, jeśli dane użyte do rozwoju modelu nie odpowiadają tym, z którymi będzie on używany, albo jeśli w danych nie będzie żadnych zależności
  • Możemy stracić dużo czasu, energii i zasobów optymalizując nasz model w złym kierunku, jeśli dane są źle dobrane

Źródła danych

  • Gotowe zbiory:
    • Otwarte wyzwania (challenge)
    • Repozytoria otwartych zbiorów danych
    • Dane udostępniane przez firmy
    • Repozytoria zbiorów komercyjnych
    • Dane wewnętrzne (np. firmy)

Źródła danych

  • Tworzenie danych:
  • Generowanie syntetyczne
    • np. generowanie korpusów mowy za pomocą TTS (syntezy mowy)
  • Crowdsourcing
  • Data scrapping

Otwarte wyzwania (shared task / challenge)

Repozytoria/wyszukiwarki otwartych zbiorów danych

Otwarte zbiory

Licencje

  • Przed podjęciem decyzji o użyciu danego zbioru koniecznie sprawdź jego licencję!
  • Wiele dostępnych w internecie zbiorów jest udostępniana na podstawie otwartych licencji
  • Zazwyczaj jednak ich użycie wymaga spełnienia pewnych warunków, np. podania źródła
  • Wiele ogólnie dostępnych zbiorów nie może być jednak użytych za darmo w celach komercyjnych!
  • Niektóre z nich mogą nawet powodować, że praca pochodna, która zostanie stworzona z ich wykorzystaniem, będzie musiała być udostępniona na tej samej licencji (GPL). Jest to "niebezpieczeństwo" w przypadku wykorzystania zasobów przez firmę komercyjną!
  • Zasady działania licencji CC: https://creativecommons.pl/
  • Najbardziej popularne licencje:
  • Przyjazne również w zastosowaniach komercyjnych: MIT, BSD, Appache, CC (bez dopisku NC)
  • GPL (GNU Public License) - "zaraźliwa" licencja Open Source

Przykład

  • Za pomocą standardowych narzędzi bash dokonamy wstępnej inspekcji i podziału danych

  • Jako przykładu użyjemy klasycznego zbioru IRIS: https://archive.ics.uci.edu/ml/datasets/Iris

  • Zbiór zawiera dane dotyczące długości i szerokości płatków kwiatowych trzech gatunków irysa:

  • Iris Setosa

  • Iris Versicolour

  • Iris Virginica

Źródło: https://www.kaggle.com/vinayshaw/iris-species-100-accuracy-using-naive-bayes
Licencja: Apache 2.0

Pobranie danych

#Zainstalujmy potrzebne biblioteki 
!pip install --user kaggle #API Kaggle, do pobrania zbioru
!pip install --user pandas
Collecting kaggle
  Using cached kaggle-1.5.12.tar.gz (58 kB)
Requirement already satisfied: six>=1.10 in /media/tomek/Linux_data/home/tomek/miniconda3/lib/python3.9/site-packages (from kaggle) (1.15.0)
Requirement already satisfied: certifi in /media/tomek/Linux_data/home/tomek/miniconda3/lib/python3.9/site-packages (from kaggle) (2021.5.30)
Requirement already satisfied: python-dateutil in /media/tomek/Linux_data/home/tomek/miniconda3/lib/python3.9/site-packages (from kaggle) (2.8.1)
Requirement already satisfied: requests in /media/tomek/Linux_data/home/tomek/miniconda3/lib/python3.9/site-packages (from kaggle) (2.25.1)
Requirement already satisfied: tqdm in /media/tomek/Linux_data/home/tomek/miniconda3/lib/python3.9/site-packages (from kaggle) (4.59.0)
Requirement already satisfied: python-slugify in /media/tomek/Linux_data/home/tomek/miniconda3/lib/python3.9/site-packages (from kaggle) (5.0.2)
Requirement already satisfied: urllib3 in /media/tomek/Linux_data/home/tomek/miniconda3/lib/python3.9/site-packages (from kaggle) (1.26.4)
Requirement already satisfied: text-unidecode>=1.3 in /media/tomek/Linux_data/home/tomek/miniconda3/lib/python3.9/site-packages (from python-slugify->kaggle) (1.3)
Requirement already satisfied: idna<3,>=2.5 in /media/tomek/Linux_data/home/tomek/miniconda3/lib/python3.9/site-packages (from requests->kaggle) (2.10)
Requirement already satisfied: chardet<5,>=3.0.2 in /media/tomek/Linux_data/home/tomek/miniconda3/lib/python3.9/site-packages (from requests->kaggle) (4.0.0)
Building wheels for collected packages: kaggle
  Building wheel for kaggle (setup.py) ... [?25ldone
[?25h  Created wheel for kaggle: filename=kaggle-1.5.12-py3-none-any.whl size=73053 sha256=1e6240d540651324d97a9772ad1ced30da7d7b5dc5956dc974eeeddf7c48844b
  Stored in directory: /home/tomek/.cache/pip/wheels/ac/b2/c3/fa4706d469b5879105991d1c8be9a3c2ef329ba9fe2ce5085e
Successfully built kaggle
Installing collected packages: kaggle
Successfully installed kaggle-1.5.12
Requirement already satisfied: pandas in /media/tomek/Linux_data/home/tomek/miniconda3/lib/python3.9/site-packages (1.2.4)
Requirement already satisfied: python-dateutil>=2.7.3 in /media/tomek/Linux_data/home/tomek/miniconda3/lib/python3.9/site-packages (from pandas) (2.8.1)
Requirement already satisfied: numpy>=1.16.5 in /media/tomek/Linux_data/home/tomek/miniconda3/lib/python3.9/site-packages (from pandas) (1.20.2)
Requirement already satisfied: pytz>=2017.3 in /media/tomek/Linux_data/home/tomek/miniconda3/lib/python3.9/site-packages (from pandas) (2021.1)
Requirement already satisfied: six>=1.5 in /media/tomek/Linux_data/home/tomek/miniconda3/lib/python3.9/site-packages (from python-dateutil>=2.7.3->pandas) (1.15.0)
# Żeby poniższa komenda zadziałała, musisz posiadać plik ~/.kaggle/kaggle.json, zawierający Kaggle API token.
# Instrukcje: https://www.kaggle.com/docs/api
!kaggle datasets download -d uciml/iris
Downloading iris.zip to /home/tomek/AITech/repo/aitech-ium
  0%|                                               | 0.00/3.60k [00:00<?, ?B/s]
100%|██████████████████████████████████████| 3.60k/3.60k [00:00<00:00, 1.63MB/s]
!unzip -o iris.zip
Archive:  iris.zip
  inflating: Iris.csv                
  inflating: database.sqlite         

Inspekcja

  • Zanim zaczniemy trenować model na danych, powinniśmy poznać ich specyfikę
  • Pozwoli nam to:
    • usunąć lub naprawić nieprawidłowe przykłady
    • dokonać selekcji cech, których użyjemy w naszym modelu
    • wybrać odpowiedni algorytm uczenia
    • podjąć dezycję dotyczącą podziału zbioru i ewentualnej normalizacji

Inspekcja

!pip install --user pandas
!pip install --user seaborn
Requirement already satisfied: pandas in /media/tomek/Linux_data/home/tomek/miniconda3/lib/python3.9/site-packages (1.2.4)
Requirement already satisfied: pytz>=2017.3 in /media/tomek/Linux_data/home/tomek/miniconda3/lib/python3.9/site-packages (from pandas) (2021.1)
Requirement already satisfied: numpy>=1.16.5 in /media/tomek/Linux_data/home/tomek/miniconda3/lib/python3.9/site-packages (from pandas) (1.20.2)
Requirement already satisfied: python-dateutil>=2.7.3 in /media/tomek/Linux_data/home/tomek/miniconda3/lib/python3.9/site-packages (from pandas) (2.8.1)
Requirement already satisfied: six>=1.5 in /media/tomek/Linux_data/home/tomek/miniconda3/lib/python3.9/site-packages (from python-dateutil>=2.7.3->pandas) (1.15.0)
Collecting seaborn
  Downloading seaborn-0.11.2-py3-none-any.whl (292 kB)
     |████████████████████████████████| 292 kB 1.1 MB/s eta 0:00:01
[?25hCollecting matplotlib>=2.2
  Downloading matplotlib-3.5.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl (11.2 MB)
     |████████████████████████████████| 11.2 MB 10.8 MB/s eta 0:00:01
[?25hRequirement already satisfied: pandas>=0.23 in /media/tomek/Linux_data/home/tomek/miniconda3/lib/python3.9/site-packages (from seaborn) (1.2.4)
Requirement already satisfied: numpy>=1.15 in /media/tomek/Linux_data/home/tomek/miniconda3/lib/python3.9/site-packages (from seaborn) (1.20.2)
Requirement already satisfied: scipy>=1.0 in /media/tomek/Linux_data/home/tomek/miniconda3/lib/python3.9/site-packages (from seaborn) (1.6.3)
Requirement already satisfied: packaging>=20.0 in /media/tomek/Linux_data/home/tomek/miniconda3/lib/python3.9/site-packages (from matplotlib>=2.2->seaborn) (20.9)
Requirement already satisfied: python-dateutil>=2.7 in /media/tomek/Linux_data/home/tomek/miniconda3/lib/python3.9/site-packages (from matplotlib>=2.2->seaborn) (2.8.1)
Collecting cycler>=0.10
  Downloading cycler-0.11.0-py3-none-any.whl (6.4 kB)
Requirement already satisfied: pyparsing>=2.2.1 in /media/tomek/Linux_data/home/tomek/miniconda3/lib/python3.9/site-packages (from matplotlib>=2.2->seaborn) (2.4.7)
Collecting fonttools>=4.22.0
  Downloading fonttools-4.30.0-py3-none-any.whl (898 kB)
     |████████████████████████████████| 898 kB 4.9 MB/s eta 0:00:01
[?25hRequirement already satisfied: pillow>=6.2.0 in /media/tomek/Linux_data/home/tomek/miniconda3/lib/python3.9/site-packages (from matplotlib>=2.2->seaborn) (8.2.0)
Collecting kiwisolver>=1.0.1
  Downloading kiwisolver-1.3.2-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl (1.6 MB)
     |████████████████████████████████| 1.6 MB 7.7 MB/s eta 0:00:01
[?25hRequirement already satisfied: pytz>=2017.3 in /media/tomek/Linux_data/home/tomek/miniconda3/lib/python3.9/site-packages (from pandas>=0.23->seaborn) (2021.1)
Requirement already satisfied: six>=1.5 in /media/tomek/Linux_data/home/tomek/miniconda3/lib/python3.9/site-packages (from python-dateutil>=2.7->matplotlib>=2.2->seaborn) (1.15.0)
Installing collected packages: kiwisolver, fonttools, cycler, matplotlib, seaborn
Successfully installed cycler-0.11.0 fonttools-4.30.0 kiwisolver-1.3.2 matplotlib-3.5.1 seaborn-0.11.2
!head -n 5 Iris.csv
Id,SepalLengthCm,SepalWidthCm,PetalLengthCm,PetalWidthCm,Species
1,5.1,3.5,1.4,0.2,Iris-setosa
2,4.9,3.0,1.4,0.2,Iris-setosa
3,4.7,3.2,1.3,0.2,Iris-setosa
4,4.6,3.1,1.5,0.2,Iris-setosa
import pandas as pd
iris=pd.read_csv('Iris.csv')
iris
Id SepalLengthCm SepalWidthCm PetalLengthCm PetalWidthCm Species
0 1 5.1 3.5 1.4 0.2 Iris-setosa
1 2 4.9 3.0 1.4 0.2 Iris-setosa
2 3 4.7 3.2 1.3 0.2 Iris-setosa
3 4 4.6 3.1 1.5 0.2 Iris-setosa
4 5 5.0 3.6 1.4 0.2 Iris-setosa
... ... ... ... ... ... ...
145 146 6.7 3.0 5.2 2.3 Iris-virginica
146 147 6.3 2.5 5.0 1.9 Iris-virginica
147 148 6.5 3.0 5.2 2.0 Iris-virginica
148 149 6.2 3.4 5.4 2.3 Iris-virginica
149 150 5.9 3.0 5.1 1.8 Iris-virginica

150 rows × 6 columns

iris.describe(include='all')
Id SepalLengthCm SepalWidthCm PetalLengthCm PetalWidthCm Species
count 150.000000 150.000000 150.000000 150.000000 150.000000 150
unique NaN NaN NaN NaN NaN 3
top NaN NaN NaN NaN NaN Iris-virginica
freq NaN NaN NaN NaN NaN 50
mean 75.500000 5.843333 3.054000 3.758667 1.198667 NaN
std 43.445368 0.828066 0.433594 1.764420 0.763161 NaN
min 1.000000 4.300000 2.000000 1.000000 0.100000 NaN
25% 38.250000 5.100000 2.800000 1.600000 0.300000 NaN
50% 75.500000 5.800000 3.000000 4.350000 1.300000 NaN
75% 112.750000 6.400000 3.300000 5.100000 1.800000 NaN
max 150.000000 7.900000 4.400000 6.900000 2.500000 NaN
iris["Species"].value_counts()
Iris-virginica     50
Iris-setosa        50
Iris-versicolor    50
Name: Species, dtype: int64
iris["Species"].value_counts().plot(kind="bar")
<AxesSubplot:>
iris[["Species","PetalLengthCm"]].groupby("Species").mean()
PetalLengthCm
Species
Iris-setosa 1.464
Iris-versicolor 4.260
Iris-virginica 5.552
iris[["Species","PetalLengthCm"]].groupby("Species").mean().plot(kind="bar")
<AxesSubplot:xlabel='Species'>
import seaborn as sns
sns.set_theme()
sns.relplot(data=iris, x="PetalLengthCm", y="PetalWidthCm", hue="Species")
sns.relplot(data=iris, x="SepalLengthCm", y="SepalWidthCm", hue="Species")
<seaborn.axisgrid.FacetGrid at 0x7f97eed545b0>
irisv = iris[iris["Species"] !=  "Iris-setosa"]
sns.relplot(data=irisv, x="SepalLengthCm", y="SepalWidthCm", hue="Species")
<seaborn.axisgrid.FacetGrid at 0x7f97ef942eb0>
sns.pairplot(data=iris.drop(columns=["Id"]), hue="Species")
<seaborn.axisgrid.PairGrid at 0x7f97f2ad3550>

Podział danych

  • Zbiór trenujący ("training set")

  • Służy do dopasowania parametrów modelu (np. wag w sieci neuronowej).
  • Podczas trenowania algorytm minimalizuje funkcję kosztu obliczoną na zbiorze treningowym
  • Zbiór walidujący/walidacyjny ("validation set" aka. "dev set")

  • Służy do porównania modeli powstałych przy użyciu różnych hiperparametrów (np. architektura sieci, ilość iteracji trenowania)
  • Pomaga uniknąć przetrenowania (overfitting) modelu na zbiorze trenującym poprzez zastosowanie tzw. early stopping
  • Zbiór testujący ("test set")

  • Służy do ewaluacji finalnego modelu wybranego/wytrenowanego za pomocą zbiorów trenującego i walidującego

Podział danych

  • Zbiory trenujący, walidacyjny i testowy powinny być niezależne, ale pochodzić z tego samego rozkładu
  • W przypadku klasyfikacji, rozkład klas w zbiorach powinien być zbliżony
  • Bardzo istotne jest to, żeby zbiory walidujący i testujący dobrze odzwierciedlały nasze cele biznesowe i rzeczywiste dane, na których będzie działał nasz model

Metody podziału:

  • Skorzystać z gotowego podziału danych :)
  • Jeśli dzielimy zbiór sami:
    • "Klasyczne" podejście: proporcja Train:Dev:Test 6:2:2 lub 8:1:1
    • Uczenie głębokie:
      • metody "głębokie" mają bardzo duże zapotrzebowanie na dane, zbiory rzędu > 1 000 000 przykładów
      • Załóżmy, że cały zbiór ma 1 000 000 przykładów
      • wielkości zbiorów dev i test ustalamy bezwzględnie, np. na 1000 albo 10 000 przykładów
      • 10 000 przykładów to (wystarczająco) dużo, choć stanowi jedynie 1% z całego zbioru
      • szkoda "marnować" dodatkowe 180 000 przykładów na zbiory testujące i walidacyjne, lepiej mieć większy zbiór trenujący

Przykładowy podział z pomocą standardowych narzędzi Bash

# Pobierzmy plik ze zbiorem z repozytorium
!cd IUM_02; wget -c https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data
--2021-03-15 11:16:36--  https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data
Resolving archive.ics.uci.edu (archive.ics.uci.edu)... 128.195.10.252
Connecting to archive.ics.uci.edu (archive.ics.uci.edu)|128.195.10.252|:443... connected.
HTTP request sent, awaiting response... 416 Requested Range Not Satisfiable

    The file is already fully retrieved; nothing to do.

#Sprawdźmy wielkość zbioru
!wc -l IUM_02/iris.data
151 IUM_02/iris.data
#Sprawdźmy strukturę
!head -n 5 IUM_02/iris.data
5.1,3.5,1.4,0.2,Iris-setosa
4.9,3.0,1.4,0.2,Iris-setosa
4.7,3.2,1.3,0.2,Iris-setosa
4.6,3.1,1.5,0.2,Iris-setosa
5.0,3.6,1.4,0.2,Iris-setosa
#Sprawdźmy jakie są klasy i ile każda ma przykładów:
!cut -f 5 -d "," IUM_02/iris.data | sort | uniq -c
      1 
     50 Iris-setosa
     50 Iris-versicolor
     50 Iris-virginica
# Znajdźmy pustą linijkę:
! grep -P "^$" -n IUM_02/iris.data
151:
#Usuwamy pustą linijkę i tasujemy plik:
! head -n -1 IUM_02/iris.data | shuf > IUM_02/iris.data.shuf
# Dzielimy zbiór w proporcji 4:1:1
!head -n 25 IUM_02/iris.data.shuf > IUM_02/iris.data.test
!head -n 50 IUM_02/iris.data.shuf | tail -n 25 > IUM_02/iris.data.dev
!tail -n +51 IUM_02/iris.data.shuf > IUM_02/iris.data.train
!rm IUM_02/iris.data.shuf
#Sprawdźmy, czy wielkości się zgadzają:
!wc -l IUM_02/iris.data*
 151 IUM_02/iris.data
  25 IUM_02/iris.data.dev
  25 IUM_02/iris.data.test
 100 IUM_02/iris.data.train
 301 total
!cut -f 5 -d "," IUM_02/iris.data.train | sort | uniq -c
     33 Iris-setosa
     36 Iris-versicolor
     31 Iris-virginica
!cut -f 5 -d "," IUM_02/iris.data.dev | sort | uniq -c
      7 Iris-setosa
      9 Iris-versicolor
      9 Iris-virginica
!cut -f 5 -d "," IUM_02/iris.data.test | sort | uniq -c
     10 Iris-setosa
      5 Iris-versicolor
     10 Iris-virginica

Podział z pomocą sckikit learn

from sklearn.model_selection import train_test_split
iris_train, iris_test = sklearn.model_selection.train_test_split(iris, test_size=50, random_state=1)
iris_train["Species"].value_counts()
Iris-virginica     36
Iris-setosa        33
Iris-versicolor    31
Name: Species, dtype: int64
iris_test["Species"].value_counts()
Iris-versicolor    19
Iris-setosa        17
Iris-virginica     14
Name: Species, dtype: int64
from sklearn.model_selection import train_test_split
iris_train, iris_test = sklearn.model_selection.train_test_split(iris, test_size=50, random_state=1, stratify=iris["Species"])
iris_train["Species"].value_counts()
Iris-setosa        34
Iris-virginica     33
Iris-versicolor    33
Name: Species, dtype: int64
iris_test["Species"].value_counts()
Iris-virginica     17
Iris-versicolor    17
Iris-setosa        16
Name: Species, dtype: int64

Preprocessing danych

  • Czyszczenie
    • usuwanie ze zbioru przykładów nieprawidłowych
    • korekta nieprawidłowych wartości
  • Normalizacja
    • Dane numeryczne: skalowanie do zakresu, np. [0.0, 1.0] (https://scikit-learn.org/stable/modules/preprocessing.html)
    • Dane tekstowe: lowercase, ujednolicenie wariantów pisowni, normalizacja wyrażeń numerycznych
    • Dane obrazowe: normalizacja rozdzielczości, palety kolorów
    • Dane dźwiękowe: normalizacja natężenia, rozdzielczości, częstotliwości próbkowania, ilości kanałów
  • Poszerzanie (augumentacja) danych
    • Generowanie nowych przykładów przez wprowadzanie szumu/przekształceń na originalnych danych
    • np. dodanie echa do nagrania dźwiękowego, dodanie szumów do obrazka
    • zmiana wartości cech o względnie małe, losowe wartości
  • Over/under-sampling
    • Algorymty uczące i metryki mogą być wrażliwe na niezbalansowane klasy w zbiorze
    • Np. jeśli w zbiorze są 2 klasy w propocji 9:1, to najprostszy "klasyfikator" bez problemy osiągnie accuracy 90%
    • Najprostszy sposób: skopiujmy (albo usuńmy) część przykładów zwiększając (lub zmniejszając) dany zbiór

Zadanie [5pkt]

  • Wybierz jeden z ogólnodostępnych zbiorów danych. Będziesz na nim pracował do końca roku (oczywiście, zbiór można zmienić w trakcie, ale będzie się to wiązało z powtarzeniem pewnych działań, co prawdwa niezbyt kosztownych, ale jednak).

  • Zbiór powinien być:

  • nie za duży (max 50 MB)

  • nie za mały (np. IRIS jest za mały ;))

  • unikalny (każda osoba w grupie pracuje na innym zbiorze). W celu synchronizacji, wybrany przez siebie zbiór proszę zapisać tutaj: https://uam.sharepoint.com//s/2022SL06-DIUMUI0LABInynieriauczeniamaszynowego-Grupa11/EaID4LM20YhOhxxL-VHxPogBCTq4uXpLHQAzrCeDzPv1dw?e=HfXKqB

  • najlepiej, żeby był to zbiór zawierający dane w formie tekstowej, mogący posłużyć do zadania klasyfikacji lub rergesji - na takim zbiorze będzie łatwiej pracować niż np. na zbiorze obrazów albo dźwięków. Dzięki temu będziesz się mogła/mógł skupić na istocie tych zajęć.

  • Napisz skrypt, który:

  1. Pobierze wybrany przez Ciebie zbiór
  2. Jeśli brak w zbiorze gotowego podziału na podzbiory train/dev/test, to dokona takiego podziału
  3. Zbierze i wydrukuje statystyki dla tego zbioru i jego podzbiorów, takie jak np.:
  • wielkość zbioru i podzbiorów
  • średnią, minimum, maksimum, odchylenia standardowe, medianę wartości poszczególnych parametrów)
  • rozkład częstości przykładów dla poszczególnych klas
  1. Dokona normalizacji danych w zbiorze (np. normalizacja wartości float do zakresu 0.0 - 1.0)
  2. Wyczyści zbiór z artefaktów (np. puste linie, przykłady z niepoprawnymi wartościami)