874 lines
32 KiB
Plaintext
874 lines
32 KiB
Plaintext
{
|
||
"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",
|
||
"* [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)"
|
||
]
|
||
},
|
||
{
|
||
"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 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/"
|
||
]
|
||
}
|
||
],
|
||
"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
|
||
}
|