uczenie-maszynowe/lab/04_Reprezentacja_danych.ipynb
2022-11-24 07:22:33 +01:00

874 lines
32 KiB
Plaintext
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "-"
}
},
"source": [
"### Uczenie maszynowe — laboratoria\n",
"# 4. Reprezentacja danych"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Na tych zajęciach dowiemy się, w jaki sposób reprezentować różnego rodzaju dane tak, żeby można było używać ich do uczenia maszynowego."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Plik *mieszkania4.tsv* zawiera dane wydobyte z serwisu *gratka.pl* dotyczące cen mieszkań w Poznaniu."
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
" 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:"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[ 46 59 79 63 90 66 32 38 68 43 185 64\n",
" 165 71 73 51 70 48 42 33 203 88 41 31\n",
" 45 62 60 295 53 84 170 56 47 228 44 67\n",
" 49 37 87 36 55 57 118 65 30 28 230 54\n",
" 52 95 50 26 171 282 77 40 150 300 39 145\n",
" 370 140 225 29 61 135 27 270 177 85 92 132\n",
" 75 200 74 219 220 96 235 20 153 318 104 58\n",
" 72 117 189 81 111 35 280 141 195 120 250 97\n",
" 154 114 76 287 34 180 160 176 148 98 217 86\n",
" 260 198 78 183 80 163 82 100 156 320 89 103\n",
" 159 125 340 149 175 237 110 182 186 106 233 197\n",
" 136 162 157 240 211 83 196 69 102 91 108 130\n",
" 510 143 1200 178 226 190 151 138 161 142 683 146\n",
" 94 109 263 112 855 376 218 113 215 264 139 129\n",
" 167 600 24 174 296 315 232 298 330 93 301 127\n",
" 290 275 375 124 252 173 158 25 269 128 192 155\n",
" 99 126 147 288 119 206 105 224 346 339 204 1100\n",
" 392 243 101 18 202 205 107 199 137 134 144 216\n",
" 172 239 116 364 121 23 267 369 11930 122 400 209\n",
" 210 268 500 123 245 15 22 335 262 438 307 184\n",
" 354 249 431 214 164 328 800 16 229 152 650 241\n",
" 187 276 297 443 353 360 350 213 19 265]\n"
]
}
],
"source": [
"print(pd.unique(alldata[\"Powierzchnia w m2\"]))\n",
"\n",
"# (funkcja `pandas.unique` służy do pomijania duplikatów wartości)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Czasami w danej kolumnie oprócz liczb występują również inne wartości. Przykładem takiej cechy może być *Piętro*:"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"['parter' '2' '5' '12' '1' '3' nan '8' '4' '16' '7' '6' 'poddasze' '9'\n",
" '11' '13' '14' '10' '15' 'niski parter']\n"
]
}
],
"source": [
"print(pd.unique(alldata[\"Piętro\"]))\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Jak widać powyżej, tutaj oprócz liczb pojawiają się pewne tekstowe wartości specjalne, takie jak `parter`, `poddasze` czy `niski parter`."
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"1 897\n",
"parter 833\n",
"2 719\n",
"3 669\n",
"4 549\n",
"5 260\n",
"7 78\n",
"8 63\n",
"9 59\n",
"6 55\n",
"11 39\n",
"12 35\n",
"10 32\n",
"13 25\n",
"14 25\n",
"16 11\n",
"poddasze 5\n",
"15 4\n",
"niski parter 1\n",
"Name: Piętro, dtype: int64"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Sprawdźmy, jak często pojawiają się poszczególne wartości.\n",
"alldata[\"Piętro\"].value_counts()\n"
]
},
{
"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*?\n",
" * Skoro `poddasze` pojawia się tylko w nielicznych przykładach, może w ogóle odrzucić te przykłady?"
]
},
{
"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`."
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Przed zamianą:\n",
"122 1\n",
"123 2\n",
"124 poddasze\n",
"125 5\n",
"126 parter\n",
"127 3\n",
"Name: Piętro, dtype: object\n"
]
}
],
"source": [
"print(\"Przed zamianą:\")\n",
"print(alldata[\"Piętro\"][122:128])\n"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"Po zamianie:\n",
"122 1.0\n",
"123 2.0\n",
"124 NaN\n",
"125 5.0\n",
"126 0.0\n",
"127 3.0\n",
"Name: Piętro, dtype: float64\n"
]
}
],
"source": [
"# Zamiana wartości 'parter' i 'niski parter' w kolumnie 'Piętro' na 0.\n",
"alldata[\"Piętro\"] = alldata[\"Piętro\"].apply(\n",
" lambda x: 0 if x in [\"parter\", \"niski parter\"] else x\n",
")\n",
"\n",
"# Zamiana wszystkich wartości w kolumnie 'Piętro' na numeryczne.\n",
"# Parametr errors='coerce' powoduje, że napotkane nieliczbowe wartości będą zamieniane na NaN.\n",
"alldata[\"Piętro\"] = alldata[\"Piętro\"].apply(pd.to_numeric, errors=\"coerce\")\n",
"\n",
"print()\n",
"print(\"Po zamianie:\")\n",
"print(alldata[\"Piętro\"][122:128])\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Wartości NaN"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"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:"
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"nan\n",
"nan\n",
"nan\n",
"nan\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"/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",
"* [Whats 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)"
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Liczba rekordów przed usunięciem NaN: 4938\n",
"Liczba rekordów po usunięciu NaN: 888\n"
]
}
],
"source": [
"print(\"Liczba rekordów przed usunięciem NaN:\", len(alldata))\n",
"\n",
"alldata = alldata.dropna() # usunięcie rekordów zawierających NaN\n",
"\n",
"print(\"Liczba rekordów po usunięciu NaN:\", len(alldata))\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Dane boole'owskie"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"W przypadku danych typu prawda/fałsz, wystarczy zamienić wartości `True` na `1`, a `False` na `0`:"
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Przed zamianą:\n",
"0 False\n",
"1 False\n",
"2 False\n",
"3 True\n",
"13 False\n",
" ... \n",
"4909 False\n",
"4917 True\n",
"4918 False\n",
"4920 False\n",
"4937 False\n",
"Name: Garaż, Length: 888, dtype: bool\n"
]
}
],
"source": [
"print(\"Przed zamianą:\")\n",
"print(alldata[\"Garaż\"])\n"
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"Po zamianie:\n",
"0 0\n",
"1 0\n",
"2 0\n",
"3 1\n",
"13 0\n",
" ..\n",
"4909 0\n",
"4917 1\n",
"4918 0\n",
"4920 0\n",
"4937 0\n",
"Name: Garaż, Length: 888, dtype: int64\n"
]
}
],
"source": [
"alldata[\"Garaż\"] = alldata[\"Garaż\"].apply(lambda x: 1 if x == True else 0)\n",
"\n",
"print()\n",
"print(\"Po zamianie:\")\n",
"print(alldata[\"Garaż\"])\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Dane kategoryczne"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"O danych kategorycznych mówimy, jeżeli dane mogą przyjmować wartości ze skończonej listy („kategorii”), np.:"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"['apartamentowiec', 'kamienica', 'blok', 'dom wielorodzinny/szeregowiec', 'plomba']\n"
]
}
],
"source": [
"# \"Typ zabudowy\" może przyjmować jedną z następujących wartości:\n",
"\n",
"typ_zabudowy_values = list(pd.unique(alldata[\"Typ zabudowy\"]))\n",
"\n",
"print(typ_zabudowy_values)\n"
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"['cegła', 'płyta', 'inne', 'pustak', 'silikat', 'beton']\n"
]
}
],
"source": [
"# \"Materiał budynku\" może przyjmować jedną z następujących wartości:\n",
"\n",
"material_budynku_values = list(pd.unique(alldata[\"Materiał budynku\"]))\n",
"\n",
"print(material_budynku_values)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Cechę kategoryczną można rozbić na skończoną liczbę cech boole'owskich:"
]
},
{
"cell_type": "code",
"execution_count": 26,
"metadata": {},
"outputs": [],
"source": [
"# Skopiujmy dane, żeby przedstawić 2 alternatywne rozwiązania\n",
"\n",
"alldata_1 = alldata.copy()\n",
"alldata_2 = alldata.copy()\n"
]
},
{
"cell_type": "code",
"execution_count": 27,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Nowo utworzone kolumny (cechy boole'owskie):\n",
"['Czy apartamentowiec?', 'Czy kamienica?', 'Czy blok?', 'Czy dom wielorodzinny/szeregowiec?', 'Czy plomba?']\n",
"\n",
" Typ zabudowy Czy apartamentowiec? Czy kamienica? \\\n",
"0 apartamentowiec True False \n",
"1 kamienica False True \n",
"2 blok False False \n",
"3 blok False False \n",
"13 blok False False \n",
"... ... ... ... \n",
"4909 apartamentowiec True False \n",
"4917 dom wielorodzinny/szeregowiec False False \n",
"4918 blok False False \n",
"4920 dom wielorodzinny/szeregowiec False False \n",
"4937 dom wielorodzinny/szeregowiec False False \n",
"\n",
" Czy blok? Czy dom wielorodzinny/szeregowiec? Czy plomba? \n",
"0 False False False \n",
"1 False False False \n",
"2 True False False \n",
"3 True False False \n",
"13 True False False \n",
"... ... ... ... \n",
"4909 False False False \n",
"4917 False True False \n",
"4918 True False False \n",
"4920 False True False \n",
"4937 False True False \n",
"\n",
"[888 rows x 6 columns]\n"
]
}
],
"source": [
"# Rozwiązanie 1\n",
"\n",
"select_column_names = []\n",
"for typ_zabudowy in typ_zabudowy_values:\n",
" new_column_name = \"Czy {}?\".format(typ_zabudowy)\n",
" alldata_1[new_column_name] = alldata_1[\"Typ zabudowy\"] == typ_zabudowy\n",
" select_column_names.append(new_column_name)\n",
"\n",
"print(\"Nowo utworzone kolumny (cechy boole'owskie):\")\n",
"print(select_column_names)\n",
"\n",
"select_column_names = [\"Typ zabudowy\"] + select_column_names\n",
"\n",
"print()\n",
"\n",
"print(alldata_1[select_column_names])\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"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`:"
]
},
{
"cell_type": "code",
"execution_count": 28,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
" cena Powierzchnia w m2 Liczba pokoi Garaż Liczba pięter w budynku \\\n",
"0 290386 46 2 0 5.0 \n",
"1 450000 59 2 0 3.0 \n",
"2 375000 79 3 0 16.0 \n",
"3 400000 63 3 1 2.0 \n",
"13 450000 64 3 0 4.0 \n",
"... ... ... ... ... ... \n",
"4909 141300 46 2 0 1.0 \n",
"4917 710000 120 4 1 1.0 \n",
"4918 858000 120 5 0 3.0 \n",
"4920 399000 69 3 0 2.0 \n",
"4937 127900 36 2 0 2.0 \n",
"\n",
" Piętro Rok budowy opis \\\n",
"0 0.0 2017.0 Polecam mieszkanie 2 pokojowe o metrażu 46,68 ... \n",
"1 2.0 1902.0 Ekskluzywna oferta - tylko u nas! Projekt arch... \n",
"2 5.0 1990.0 Polecam do kupna przestronne mieszkanie trzypo... \n",
"3 2.0 2009.0 Dla rodziny albo pod wynajem. Świetna lokaliza... \n",
"13 2.0 1992.0 Witam,Mam na imię Jędrzej i w biurze Platan po... \n",
"... ... ... ... \n",
"4909 0.0 2014.0 !!! Apartamenty w Lusówku oddawane w stanie de... \n",
"4917 0.0 2013.0 Sprzedam lokal mieszkalny odrębna własność w b... \n",
"4918 3.0 1993.0 Polecam do kupna mieszkanie 5 pokojowe o pow. ... \n",
"4920 1.0 2008.0 Przestronne mieszkanie z pięknym widokiem!Dwup... \n",
"4937 2.0 2018.0 Sprzedaż nowego mieszkania w FAŁKOWIE - Osiedl... \n",
"\n",
" Typ zabudowy_apartamentowiec Typ zabudowy_blok \\\n",
"0 1 0 \n",
"1 0 0 \n",
"2 0 1 \n",
"3 0 1 \n",
"13 0 1 \n",
"... ... ... \n",
"4909 1 0 \n",
"4917 0 0 \n",
"4918 0 1 \n",
"4920 0 0 \n",
"4937 0 0 \n",
"\n",
" Typ zabudowy_dom wielorodzinny/szeregowiec Typ zabudowy_kamienica \\\n",
"0 0 0 \n",
"1 0 1 \n",
"2 0 0 \n",
"3 0 0 \n",
"13 0 0 \n",
"... ... ... \n",
"4909 0 0 \n",
"4917 1 0 \n",
"4918 0 0 \n",
"4920 1 0 \n",
"4937 1 0 \n",
"\n",
" Typ zabudowy_plomba Materiał budynku_beton Materiał budynku_cegła \\\n",
"0 0 0 1 \n",
"1 0 0 1 \n",
"2 0 0 0 \n",
"3 0 0 1 \n",
"13 0 0 1 \n",
"... ... ... ... \n",
"4909 0 0 1 \n",
"4917 0 0 1 \n",
"4918 0 0 1 \n",
"4920 0 0 1 \n",
"4937 0 0 1 \n",
"\n",
" Materiał budynku_inne Materiał budynku_pustak Materiał budynku_płyta \\\n",
"0 0 0 0 \n",
"1 0 0 0 \n",
"2 0 0 1 \n",
"3 0 0 0 \n",
"13 0 0 0 \n",
"... ... ... ... \n",
"4909 0 0 0 \n",
"4917 0 0 0 \n",
"4918 0 0 0 \n",
"4920 0 0 0 \n",
"4937 0 0 0 \n",
"\n",
" Materiał budynku_silikat \n",
"0 0 \n",
"1 0 \n",
"2 0 \n",
"3 0 \n",
"13 0 \n",
"... ... \n",
"4909 0 \n",
"4917 0 \n",
"4918 0 \n",
"4920 0 \n",
"4937 0 \n",
"\n",
"[888 rows x 19 columns]\n"
]
}
],
"source": [
"alldata_2 = pd.get_dummies(alldata_2, columns=[\"Typ zabudowy\", \"Materiał budynku\"])\n",
"\n",
"print(alldata_2)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"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 use pandas.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:"
]
},
{
"cell_type": "code",
"execution_count": 29,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
" nowe_w_opisie opis\n",
"0 True Polecam mieszkanie 2 pokojowe o metrażu 46,68 ...\n",
"1 False Ekskluzywna oferta - tylko u nas! Projekt arch...\n",
"2 False Polecam do kupna przestronne mieszkanie trzypo...\n",
"3 False Dla rodziny albo pod wynajem. Świetna lokaliza...\n",
"13 False Witam,Mam na imię Jędrzej i w biurze Platan po...\n",
"... ... ...\n",
"4909 True !!! Apartamenty w Lusówku oddawane w stanie de...\n",
"4917 False Sprzedam lokal mieszkalny odrębna własność w b...\n",
"4918 False Polecam do kupna mieszkanie 5 pokojowe o pow. ...\n",
"4920 True Przestronne mieszkanie z pięknym widokiem!Dwup...\n",
"4937 True Sprzedaż nowego mieszkania w FAŁKOWIE - Osiedl...\n",
"\n",
"[888 rows x 2 columns]\n"
]
}
],
"source": [
"alldata[\"nowe_w_opisie\"] = alldata[\"opis\"].apply(\n",
" 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 TFIDF, 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/"
]
}
],
"metadata": {
"celltoolbar": "Slideshow",
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.6"
},
"livereveal": {
"start_slideshow_at": "selected",
"theme": "amu"
},
"vscode": {
"interpreter": {
"hash": "916dbcbb3f70747c44a77c7bcd40155683ae19c65e1c03b4aa3499c5328201f1"
}
}
},
"nbformat": 4,
"nbformat_minor": 4
}