" cena Powierzchnia w m2 Liczba pokoi Garaż Liczba pięter w budynku \\\n",
"0 290386 46 2 False 5.0 \n",
"1 450000 59 2 False 3.0 \n",
"2 375000 79 3 False 16.0 \n",
"3 400000 63 3 True 2.0 \n",
"4 389285 59 3 False 13.0 \n",
"\n",
" Piętro Typ zabudowy Materiał budynku Rok budowy \\\n",
"0 parter apartamentowiec cegła 2017.0 \n",
"1 2 kamienica cegła 1902.0 \n",
"2 5 blok płyta 1990.0 \n",
"3 2 blok cegła 2009.0 \n",
"4 12 blok NaN NaN \n",
"\n",
" opis \n",
"0 Polecam mieszkanie 2 pokojowe o metrażu 46,68 ... \n",
"1 Ekskluzywna oferta - tylko u nas! Projekt arch... \n",
"2 Polecam do kupna przestronne mieszkanie trzypo... \n",
"3 Dla rodziny albo pod wynajem. Świetna lokaliza... \n",
"4 NaN \n"
]
}
],
"source": [
"# Wczytanie danych (mieszkania) przy pomocy biblioteki pandas\n",
"\n",
"import numpy as np\n",
"import pandas as pd\n",
"\n",
"alldata = pd.read_csv(\n",
" \"mieszkania4.tsv\",\n",
" header=0,\n",
" sep=\"\\t\",\n",
" usecols=[\n",
" \"cena\",\n",
" \"Powierzchnia w m2\",\n",
" \"Liczba pokoi\",\n",
" \"Garaż\",\n",
" \"Liczba pięter w budynku\",\n",
" \"Piętro\",\n",
" \"Typ zabudowy\",\n",
" \"Materiał budynku\",\n",
" \"Rok budowy\",\n",
" \"opis\",\n",
" ],\n",
")\n",
"\n",
"print(alldata[:5])\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Jak widać powyżej, w pliku *mieszkania4.tsv* znajdują się dane różnych typów:\n",
"* dane numeryczne (po prostu liczby):\n",
" * cena\n",
" * powierzchnia w m<sup>2</sup>\n",
" * liczba pokoi\n",
"* dane częściowo numeryczne (liczby oraz wartości specjalne):\n",
" * liczba pięter w budynku\n",
" * piętro\n",
" * rok budowy\n",
"* dane boole'owskie (prawda/fałsz):\n",
" * garaż\n",
"* dane kategoryczne (wybór jednej z kilku kategorii):\n",
" * typ zabudowy\n",
"* dane tekstowe (dowolny tekst):\n",
" * opis"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Algorytmy uczenia maszynowego działają na danych liczbowych. Z tego powodu musimy znaleźć właściwy sposób reprezentowania pozostałych danych."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Dane numeryczne"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Dane numeryczne to takie, które są liczbami. W większości przypadków możemy na nich operować bezpośrednio. Przykładem takich danych jest kolumna *Powierzchnia w m2* z powyższego przykładu:"
"Można w tym celu wykorzystać funkcje [apply](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.apply.html?highlight=apply#pandas.DataFrame.apply) i [to_numeric](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.to_numeric.html) z biblioteki `pandas`."
"Wartość NaN (zob. też na [Wikipedii](https://pl.wikipedia.org/wiki/NaN)) – to wartość numeryczna oznaczająca „nie-liczbę”, „wartośćniezdefiniowaną”, np. niezdefiniowany wynik działania lub brak danych:"
"/tmp/ipykernel_11063/3804580172.py:1: RuntimeWarning: invalid value encountered in sqrt\n",
" print(np.sqrt(-1)) # niezdefiniowany wynik działania (pierwiastek z liczby ujemnej)\n"
]
}
],
"source": [
"print(np.sqrt(-1)) # niezdefiniowany wynik działania (pierwiastek z liczby ujemnej)\n",
"\n",
"print(alldata[\"Piętro\"][14]) # brak danych na temat piętra w rekordzie 14.\n",
"\n",
"# Jak uzyskać wartośćNaN?\n",
"print(float(\"NaN\"))\n",
"print(np.nan)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Co można zrobić z wartością NaN?\n",
"* Czasami można wartośćNaN zamienićna `0`, np. być może w kolumnie „przychód” wartość NaN oznacza brak przychodu. Należy jednak być z tym ostrożnym. **W większości przypadków wstawienie 0 zamiast NaN będzie niepoprawne**, np. „rok 0” to nie to samo co „rok nieznany”. Nawet w kolumnie „cena” wartość NaN raczej oznacza, że cena jest nieznana, a to przecież nie to samo, co „cena równa 0 zł”.\n",
"* **Najbezpieczniej jest usunąć cały rekord (wiersz), który zawiera jakąkolwiek wartość NaN**. Należy przy tym pamiętać, że pozbywamy się w ten sposób (byćmoże wartościowych) danych. Jest to istotne zwłaszcza wtedy, gdy nasze dane zawierają dużo wartości niezdefiniowanych.\n",
"* WartośćNaN można też zamienićna średnią, medianę, modę itp. z pozostałych wartości w zbiorze danych. To dobra opcja, jeżeli usunięcie całych wierszy zawierających NaN pozbawiłoby nas zbyt wielu rekordów.\n",
"* Można użyć też bardziej zaawansowanych technik, np. [MICE](https://stats.stackexchange.com/questions/421545/multiple-imputation-by-chained-equations-mice-explained) czy KNN."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Przydatne artykuły na temat usuwania wartości niezdefiniowanych ze zbioru danych:\n",
"* [Working with missing data in machine learning](https://towardsdatascience.com/working-with-missing-data-in-machine-learning-9c0a430df4ce)\n",
"* [What’s the best way to handle NaN values?](https://towardsdatascience.com/whats-the-best-way-to-handle-nan-values-62d50f738fc)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Biblioteka `pandas` dostarcza narzędzi do automatycznego usuwania wartości NaN: [dropna](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.dropna.html)"
"Nie trzeba tego robić ręcznie. Można do tego celu użyć funkcji [get_dummies](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.get_dummies.html) z biblioteki `pandas`:"
"Zwróćmy uwagę, że dzięki użyciu `get_dummies` nowe kolumny zostały utworzone i nazwane automatycznie, nie trzeba też już ręcznie konwertować wartości boole'owskich do numerycznych."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Funkcja `get_dummies` do określenia, na ile i jakich kolumn podzielić daną kolumnę kategoryczną, używa bieżącej zawartości tabeli. Dlatego należy jej użyć przed dokonaniem podziału na zbiory uczący i testowy.\n",
"\n",
"Więcej na ten temat można przeczytać w artykule [How to usepandas.get_dummies with the test set](http://fastml.com/how-to-use-pd-dot-get-dummies-with-the-test-set)."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Do preprocessingu danych kategorycznych można też użyć narzędzi z biblioteki *scikit-learn*: https://scikit-learn.org/stable/modules/preprocessing.html#encoding-categorical-features"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Dane tekstowe"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Przetwarzanie danych tekstowych to szeroki temat, którym można zapełnić cały wykład. Dlatego tutaj przedstawię tylko najważniejsze metody."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Możemy na przykład tworzyć cechy sprawdzające występowanie poszczególnych wyrazów lub ciągów znaków w tekście:"
" lambda x: True if \"nowe\" in x.lower() else False\n",
")\n",
"print(alldata[[\"nowe_w_opisie\", \"opis\"]])\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Można też zamienić tekst na wektory używając algorytmów TF–IDF, Word2Vec lub podobnych."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Ciekawy artykuł na temat przygotowywania danych tekstowych do uczenia maszynowego można znaleźć na przykład tutaj: https://machinelearningmastery.com/prepare-text-data-machine-learning-scikit-learn/"