" 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:"
"Jak widać powyżej, tutaj oprócz liczb pojawiają się pewne tekstowe wartości specjalne, takie jak `parter`, `poddasze` czy `niski parter`."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Takie wartości należy zamienić na liczby. Jak?\n",
"* Wydaje się, że `parter` czy `niski parter` można z powodzeniem potraktować jako piętro „zerowe” i zamienić na `0`.\n",
"* Z poddaszem sytuacja nie jest już tak oczywista. Czy mają Państwo jakieś propozycje?\n",
" * Może zamienić `poddasze` na wartośćNaN (zobacz poniżej)?\n",
" * Może wykorzystaćw tym celu wartość z sąsiedniej kolumny *Liczba pięter w budynku*?"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"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/"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Zadanie 7\n",
"\n",
"Na podstawie danych z pliku *flats.tsv* wytrenuj model, który przewidzi cenę mieszkania na podstawie różnych jego cech. Wykorzystaj cechy różnych typów (numeryczne, boole'owskie, kategoryczne, tekstowe). Dokonaj odpowiedniego preprocessingu danych.\n",
"\n",
"Zastanów się, jak poprawić wyniki uzyskane przez klasyfikator. Może przez stworzenie nowych cech pochodnych? Może przez odrzucenie mało wiarygodnych danych (obserwacji odstających)? Porównaj uzyskane wyniki z wynikami uzyskanymi w pierwszej części zadania."