PySpark Poradnik dla początkujących: Ucz się na PRZYKŁADACH
⚡ Inteligentne podsumowanie
PySpark jest Python API dla Apache Spark, umożliwiając analitykom uruchamianie rozproszonego przetwarzania danych, zapytań SQL i uczenia maszynowego w klastrach. Ten przewodnik instaluje go i wyjaśnia SparkKontekst i SQLContext, a następnie buduje klasyfikator regresji logistycznej.
Przed nauką PySpark, zrozumiemy:
Co to jest Apache Spark?
Spark to rozwiązanie do obsługi dużych zbiorów danych, które okazało się łatwiejsze i szybsze niż Hadoop MapReduce. Spark to oprogramowanie typu open source opracowane przez laboratorium UC Berkeley RAD w 2009 r. Od czasu jego publicznego udostępnienia w 2010 r. Spark zyskała na popularności i jest wykorzystywana w przemyśle na niespotykaną dotąd skalę.
W erze Big Data praktycy potrzebują bardziej niż kiedykolwiek szybkich i niezawodnych narzędzi do przetwarzania strumieni danych. Wcześniejsze narzędzia, takie jak MapReduce, były popularne, ale działały wolno. Aby rozwiązać ten problem, Spark oferuje rozwiązanie, które jest zarówno szybkie, jak i uniwersalne. Główna różnica między Spark i MapReduce to jest to Spark wykonuje obliczenia w pamięci podczas późniejszego na dysku twardym. Umożliwia szybki dostęp i przetwarzanie danych, skracając czas z godzin do minut.
Co to jest PySpark?
PySpark to narzędzie stworzone przez firmę Apache Spark Społeczność do korzystania Python w Spark. Umożliwia pracę z RDD (Resilient Distributed Dataset) w Python. Oferuje również PySpark Powłoka do połączenia Python API z Spark rdzeń do zainicjowania Spark Kontekst. Spark jest nazwą silnika do realizacji obliczeń klastrowych, podczas gdy PySpark is Pythonbibliotekę do użycia Spark.
Biblioteka wysyła jako pyspark pakiet na PyPI, więc pojedynczy pip install pyspark pobiera silnik Scala/JVM i most Py4J, który umożliwia Python obiekty do niego odwołują się. Wszystko poniżej bazuje na tym jednym pakiecie.
Jak działa Spark działa?
Spark Opiera się na silniku obliczeniowym, co oznacza, że zajmuje się planowaniem, dystrybucją i monitorowaniem aplikacji. Każde zadanie jest wykonywane na różnych maszynach roboczych, zwanych klastrem obliczeniowym. Klaster obliczeniowy odnosi się do podziału zadań. Jedna maszyna wykonuje jedno zadanie, podczas gdy pozostałe przyczyniają się do końcowego wyniku poprzez inne zadanie. Ostatecznie wszystkie zadania są agregowane w celu wygenerowania wyniku. Spark administrator daje przegląd 360 różnych Spark Oferty pracy.
Poniższy diagram pokazuje, w jaki sposób program sterujący przekazuje zadania maszynom roboczym, które tworzą taki klaster.
W jaki sposób Spark Maksymalna wysokość
Spark jest przeznaczony do pracy z
- Python
- Java
- Scala
- SQL
Istotną cechą Spark to ogromna ilość wbudowanych bibliotek, w tym MLlib do uczenia maszynowego. Spark jest również zaprojektowany do pracy z klastrami Hadoop i może odczytywać szeroki zakres plików, w tym dane Hive, CSV, JSON, Cassandra dane i inne.
Dlaczego warto korzystać Spark?
Jako przyszły praktyk danych powinieneś znać Pythonsłynne biblioteki: Pandy i nauka-scikitTe dwie biblioteki doskonale nadają się do eksploracji zbiorów danych o średniej wielkości. Standardowe projekty uczenia maszynowego opierają się na następującej metodologii:
- Załaduj dane na dysk
- Zaimportuj dane do pamięci urządzenia
- Przetwarzaj/analizuj dane
- Zbuduj model uczenia maszynowego
- Zapisz prognozę z powrotem na dysk
Problem pojawia się, gdy analityk danych chce przetworzyć dane, które są zbyt duże dla jednego komputera. We wczesnych etapach rozwoju analityki danych, praktycy próbkowali dane, ponieważ trenowanie na ogromnych zbiorach danych nie zawsze było konieczne. Analityk danych znajdował dobrą próbkę statystyczną, przeprowadzał dodatkową kontrolę odporności i tworzył doskonały model.
Jednak są z tym pewne problemy:
- Czy zbiór danych odzwierciedla świat rzeczywisty?
- Czy dane obejmują konkretny przykład?
- Czy model nadaje się do pobrania?
Weźmy na przykład rekomendacje użytkowników. Osoby polecające polegają na porównywaniu użytkowników z innymi użytkownikami przy ocenie ich preferencji. Jeśli specjalista ds. danych weźmie pod uwagę tylko podzbiór danych, nie będzie kohorty użytkowników, którzy będą do siebie bardzo podobni. Programy rekomendujące muszą działać na pełnym zestawie danych lub wcale.
Jakie jest rozwiązanie?
Rozwiązanie jest oczywiste od dawna, rozbicie problemu na wiele komputerów. Równoległe przetwarzanie również wiąże się z wieloma problemami. Programiści często mają problemy z pisaniem równoległego kodu i kończą na konieczności rozwiązania wielu złożonych problemów związanych z samym przetwarzaniem wieloprocesorowym.
PySpark udostępnia naukowcom zajmującym się danymi interfejs API, który może być używany do rozwiązywania problemów z równoległym przetwarzaniem danych. PySpark radzi sobie ze złożonością przetwarzania wieloprocesowego, np. dystrybucją danych, dystrybucją kodu i zbieraniem danych wyjściowych od pracowników na klastrze maszyn.
Spark może działać samodzielnie, ale najczęściej działa na platformie klastra obliczeniowego, takiej jak Hadoop. Jednak w testach i rozwoju naukowiec zajmujący się danymi może wydajnie działać Spark na swoich komputerach deweloperskich lub laptopach bez klastra
- Jedną z głównych zalet Spark jest zbudowanie architektury obejmującej zarządzanie strumieniowaniem danych, płynne zapytania o dane, przewidywanie za pomocą uczenia maszynowego i dostęp w czasie rzeczywistym do różnych analiz.
- Spark ściśle współpracuje z SQL język, czyli dane strukturalne. Umożliwia on wyszukiwanie danych w czasie rzeczywistym.
- Głównym zadaniem Data Scientist jest analiza i budowanie modeli predykcyjnych. Krótko mówiąc, Data Scientist musi umieć wyszukiwać dane za pomocą SQL, tworzyć raporty statystyczne i wykorzystywać uczenie maszynowe do tworzenia prognoz. Data Scientist poświęca znaczną część swojego czasu na oczyszczanie, transformację i analizę danych. Po przygotowaniu zbioru danych lub przepływu pracy, Data Scientist wykorzystuje różne techniki, aby odkrywać spostrzeżenia i ukryte wzorce. Manipulacja danymi powinna być niezawodna i łatwa w użyciu. Spark to właściwe narzędzie ze względu na szybkość i bogate interfejsy API.
W tym PSpark tutorial, dowiesz się jak zbudować klasyfikator za pomocą PySpark przykłady.
Jak zainstalować PySpark z AWS
Jupyter zespół zbudował obraz Dockera do uruchomienia Spark wydajnie. Poniżej znajdują się kroki, które możesz wykonać, aby zainstalować PySpark instancja w AWS.
Zapoznaj się z naszym samouczkiem na temat AWS oraz TensorFlow
Krok 1: Utwórz instancję
Przede wszystkim musisz utworzyć instancję. Przejdź do swojego konta AWS i uruchom instancję. Możesz zwiększyć pamięć do 15 g i użyć tej samej grupy zabezpieczeń, co w samouczku TensorFlow.
Krok 2: Otwórz połączenie
Otwórz połączenie i zainstaluj kontener docker. Aby uzyskać więcej szczegółów, zapoznaj się z samouczkiem z TensorFlow z Doker. Pamiętaj, że musisz znajdować się we właściwym katalogu roboczym.
Po prostu uruchom te kody, aby zainstalować Docker:
sudo yum update -y sudo yum install -y docker sudo service docker start sudo user-mod -a -G docker ec2-user exit
Krok 3: Otwórz ponownie połączenie i zainstaluj Spark
Po ponownym otwarciu połączenia możesz zainstalować obraz zawierający PySpark.
## Spark docker run -v ~/work:/home/jovyan/work -d -p 8888:8888 jupyter/pyspark-notebook ## Allow preserving Jupyter notebook sudo chown 1000 ~/work ## Install tree to see our working directory next sudo yum install -y tree
Krok 4: Otwórz Jupyter
Sprawdź pojemnik i jego nazwę
docker ps
Uruchom okno dokowane z dziennikami dokującymi, po których następuje nazwa okna dokowanego. Na przykład doker loguje zealous_goldwasser
Przejdź do przeglądarki i uruchom Jupyter. Adres to http://localhost:8888/. Wklej hasło podane przez terminal.
Uwaga: jeśli chcesz przesłać/pobrać plik na swoją maszynę AWS, możesz skorzystać z oprogramowania Cyberduck.
Jak zainstalować PySpark on Windows/Mac z Condą
Poniżej znajduje się szczegółowy proces instalacji PySpark on Windows/Mac używający Anacondy:
Aby zainstalować Spark na komputerze lokalnym zalecaną praktyką jest utworzenie nowego środowiska Conda. To nowe środowisko zostanie zainstalowane Python 3.6, Spark i wszystkie zależności.
Użytkownik Mac
cd anaconda3 touch hello-spark.yml vi hello-spark.yml
Windows System Rezerwacji Sal Smart Spaces® rozwiązuje problem zarządzania rezerwacjami sal, biurek i przestrzeni wspólnych. Zmiany w ostatniej chwili są od razu widoczne, co ułatwia pracę recepcji i użytkownikom. Kalendarz w czasie rzeczywistym pokazuje wolne zasoby, ich parametry, a nawet zaplanowane sprzątanie.
cd C:\Users\Admin\Anaconda3 echo.>hello-spark.yml notepad hello-spark.yml
Możesz edytować plik .yml. Zachowaj ostrożność przy wcięciu. Przed – wymagane są dwie spacje –
name: hello-spark
dependencies:
- python=3.6
- jupyter
- ipython
- numpy
- numpy-base
- pandas
- py4j
- pyspark
- pytz
Zapisz go i stwórz środowisko. To zajmuje trochę czasu
conda env create -f hello-spark.yml
Aby uzyskać więcej szczegółów na temat lokalizacji, zapoznaj się z samouczkiem Zainstaluj TensorFlow
Możesz sprawdzić całe środowisko zainstalowane na twoim komputerze
conda env list
Activate hello-spark
Użytkownik Mac
source activate hello-spark
Windows System Rezerwacji Sal Smart Spaces® rozwiązuje problem zarządzania rezerwacjami sal, biurek i przestrzeni wspólnych. Zmiany w ostatniej chwili są od razu widoczne, co ułatwia pracę recepcji i użytkownikom. Kalendarz w czasie rzeczywistym pokazuje wolne zasoby, ich parametry, a nawet zaplanowane sprzątanie.
activate hello-spark
Uwaga: Utworzyłeś już określone środowisko TensorFlow, aby uruchomić samouczki dotyczące TensorFlow. Wygodniej jest utworzyć nowe środowisko inne niż hello-tf. Nie ma sensu przeciążać hello-tf Spark lub inne biblioteki uczenia maszynowego.
Wyobraź sobie, że większość Twojego projektu obejmuje TensorFlow, ale musisz go użyć Spark dla jednego konkretnego projektu. Możesz ustawić środowisko TensorFlow dla całego swojego projektu i utworzyć osobne środowisko dla Spark. Możesz dodać dowolną liczbę bibliotek Spark środowisko, jak chcesz, bez ingerencji w środowisko TensorFlow. Gdy już skończysz z Sparkprojektu, możesz go usunąć bez wpływu na środowisko TensorFlow.
Jupyter
Otwarte Jupyter Notatnik i spróbuj, jeśli PySpark działa. W nowym notatniku wklej następujący PySpark przykładowy kod:
import pyspark from pyspark import SparkContext sc =SparkContext()
Po pomyślnym uruchomieniu nie zostanie wydrukowany żaden wynik, jak pokazuje zrzut ekranu notatnika poniżej.
Jeśli zostanie wyświetlony błąd, jest to prawdopodobne Java nie jest zainstalowany na twoim komputerze. Na komputerze Mac otwórz terminal i wpisz java -version, jeśli jest wersja java, upewnij się, że jest to 1.8. W Windows, przejdź do aplikacji i sprawdź, czy istnieje Java falcówka. Jeśli istnieje Java folderze, sprawdź to Java Wersja 1.8 jest zainstalowana. W chwili pisania tego tekstu PySpark nie jest kompatybilny z Java 9 i wyżej.
Uwaga dotycząca wersji: że Java 8 ograniczenie dotyczy Spark Linia 2.x używana w tym przewodniku. Aktualna Spark Wersje 3.x i 4.x działają na Java 8, 11 i 17, więc nowszy JDK będzie odpowiedni, jeśli zainstalujesz pasującą wersję PySpark wersja.
Jeśli musisz zainstalować Java, żebyś pomyślał link i pobierz jdk-8u181-windows-x64.exe
W przypadku użytkowników komputerów Mac zaleca się użycie `brew.`
brew tap caskroom/versions brew cask install java8
Zapoznaj się z tym samouczkiem krok po kroku jak zainstalować Java
Uwaga: Użyj polecenia remove, aby całkowicie usunąć środowisko.
conda env remove -n hello-spark -y
Spark Kontekst
SparkKontekst to wewnętrzny silnik, który umożliwia połączenia z klastrami. Jeśli chcesz uruchomić operację, potrzebujesz SparkKontekst.
Stwórz SparkKontekst
Przede wszystkim należy zainicjować SparkKontekst.
import pyspark from pyspark import SparkContext sc =SparkContext()
Teraz, gdy SparkKontekst jest gotowy, możesz utworzyć zbiór danych o nazwie RDD, Resilient Distributed Dataset. Obliczenia w RDD są automatycznie paralelizowane w całym klastrze.
nums= sc.parallelize([1,2,3,4])
Dostęp do pierwszego wiersza można uzyskać za pomocą polecenia take
nums.take(1)
[1]
Możesz zastosować transformację danych za pomocą funkcji lambda. W PySpark przykład poniżej, zwracasz kwadrat liczb. To transformacja mapy
squared = nums.map(lambda x: x*x).collect() for num in squared: print('%i ' % (num))
1 4 9 16
Kontekst SQL
Wygodniejszym sposobem jest użycie DataFrame. SparkKontekst jest już ustawiony, możesz go użyć do utworzenia ramki danych. Musisz również zadeklarować kontekst SQLContext.
SQLContext umożliwia połączenie silnika z różnymi źródłami danych. Służy do inicjowania funkcjonalności Spark kw.
Uwaga dotycząca wersji: SQLContext został zastąpiony przez SparkSesja w Spark 2.0 i formalnie przestarzałe w Spark 3.0. Poniższe przykłady zachowują SQLContext, ponieważ na nim działa oryginalny przewodnik; w nowoczesnym klastrze odpowiedni punkt wejścia to SparkSession.builder.getOrCreate(), który udostępnia te same metody read i createDataFrame.
from pyspark.sql import Row from pyspark.sql import SQLContext sqlContext = SQLContext(sc)
Teraz w tym Spark Tutorial Python, utwórzmy listę krotek. Każda krotka będzie zawierać imię i nazwisko osoby oraz jej wiek. Wymagane są cztery kroki:
Krok 1) Utwórz listę krotek z informacjami
[('John',19),('Smith',29),('Adam',35),('Henry',50)]
Krok 2) Zbuduj RDD
rdd = sc.parallelize(list_p)
Krok 3) Konwertuj krotki
rdd.map(lambda x: Row(name=x[0], age=int(x[1])))
Krok 4) Utwórz kontekst DataFrame
sqlContext.createDataFrame(ppl) list_p = [('John',19),('Smith',29),('Adam',35),('Henry',50)] rdd = sc.parallelize(list_p) ppl = rdd.map(lambda x: Row(name=x[0], age=int(x[1]))) DF_ppl = sqlContext.createDataFrame(ppl)
Jeśli chcesz uzyskać dostęp do typu każdej funkcji, możesz użyć printSchema()
DF_ppl.printSchema() root |-- age: long (nullable = true) |-- name: string (nullable = true)
Przykład uczenia maszynowego z PySpark
Teraz, gdy masz już krótkie pojęcie Spark i SQLContext, możesz już zbudować swój pierwszy program do uczenia maszynowego.
Poniżej przedstawiono kroki tworzenia programu uczenia maszynowego przy użyciu języka PySpark:
- Krok 1) Podstawowa obsługa PySpark
- Krok 2) Wstępne przetwarzanie danych
- Krok 3) Zbuduj potok przetwarzania danych
- Krok 4) Zbuduj klasyfikator: logistyczny
- Krok 5) Wytrenuj i oceń model
- Krok 6) Dostosuj hiperparametr
W tym PSpark W samouczku uczenia maszynowego wykorzystamy zbiór danych dla dorosłych. Celem tego samouczka jest nauczenie się korzystania z języka Py.SparkWięcej informacji na temat zestawu danych znajdziesz w tym samouczku.
Należy pamiętać, że zbiór danych nie jest znaczący i może się wydawać, że obliczenia zajmują dużo czasu. Spark jest przeznaczony do przetwarzania znacznej ilości danych. SparkWydajność biblioteki zwiększa się w porównaniu do innych bibliotek uczenia maszynowego, gdy zbiór przetwarzanych danych staje się większy.
Krok 1) Podstawowa obsługa PySpark
Przede wszystkim musisz zainicjować SQLContext, który nie jest jeszcze zainicjowany.
#from pyspark.sql import SQLContext url = "https://raw.githubusercontent.com/guru99-edu/R-Programming/master/adult_data.csv" from pyspark import SparkFiles sc.addFile(url) sqlContext = SQLContext(sc)
następnie możesz przeczytać plik cvs za pomocą sqlContext.read.csv. Aby to stwierdzić, używasz inferSchema ustawionego na True Spark aby automatycznie odgadnąć typ danych. Domyślnie jest to wartość False.
df = sqlContext.read.csv(SparkFiles.get("adult_data.csv"), header=True, inferSchema= True)
Przyjrzyjmy się typowi danych
df.printSchema() root |-- age: integer (nullable = true) |-- workclass: string (nullable = true) |-- fnlwgt: integer (nullable = true) |-- education: string (nullable = true) |-- education_num: integer (nullable = true) |-- marital: string (nullable = true) |-- occupation: string (nullable = true) |-- relationship: string (nullable = true) |-- race: string (nullable = true) |-- sex: string (nullable = true) |-- capital_gain: integer (nullable = true) |-- capital_loss: integer (nullable = true) |-- hours_week: integer (nullable = true) |-- native_country: string (nullable = true) |-- label: string (nullable = true)
Możesz zobaczyć dane za pomocą show.
df.show(5, truncate = False)
+---+----------------+------+---------+-------------+------------------+-----------------+-------------+-----+------+------------+------------+----------+--------------+-----+ |age|workclass |fnlwgt|education|education_num|marital |occupation |relationship |race |sex |capital_gain|capital_loss|hours_week|native_country|label| +---+----------------+------+---------+-------------+------------------+-----------------+-------------+-----+------+------------+------------+----------+--------------+-----+ |39 |State-gov |77516 |Bachelors|13 |Never-married |Adm-clerical |Not-in-family|White|Male |2174 |0 |40 |United-States |<=50K| |50 |Self-emp-not-inc|83311 |Bachelors|13 |Married-civ-spouse|Exec-managerial |Husband |White|Male |0 |0 |13 |United-States |<=50K| |38 |Private |215646|HS-grad |9 |Divorced |Handlers-cleaners|Not-in-family|White|Male |0 |0 |40 |United-States |<=50K| |53 |Private |234721|11th |7 |Married-civ-spouse|Handlers-cleaners|Husband |Black|Male |0 |0 |40 |United-States |<=50K| |28 |Private |338409|Bachelors|13 |Married-civ-spouse|Prof-specialty |Wife |Black|Female|0 |0 |40 |Cuba |<=50K| +---+----------------+------+---------+-------------+------------------+-----------------+-------------+-----+------+------------+------------+----------+--------------+-----+ only showing top 5 rows
Jeśli nie ustawiłeś parametru inferSchema na True, oto co dzieje się z typem: Wszystkie są w ciągu znaków.
df_string = sqlContext.read.csv(SparkFiles.get("adult.csv"), header=True, inferSchema= False) df_string.printSchema() root |-- age: string (nullable = true) |-- workclass: string (nullable = true) |-- fnlwgt: string (nullable = true) |-- education: string (nullable = true) |-- education_num: string (nullable = true) |-- marital: string (nullable = true) |-- occupation: string (nullable = true) |-- relationship: string (nullable = true) |-- race: string (nullable = true) |-- sex: string (nullable = true) |-- capital_gain: string (nullable = true) |-- capital_loss: string (nullable = true) |-- hours_week: string (nullable = true) |-- native_country: string (nullable = true) |-- label: string (nullable = true)
Aby przekonwertować zmienną ciągłą na odpowiedni format, możesz użyć przekształcenia kolumn. Możesz użyć withColumn, aby to powiedzieć Spark w której kolumnie przeprowadzić transformację.
# Import all from `sql.types` from pyspark.sql.types import * # Write a custom function to convert the data type of DataFrame columns def convertColumn(df, names, newType): for name in names: df = df.withColumn(name, df[name].cast(newType)) return df # List of continuous features CONTI_FEATURES = ['age', 'fnlwgt','capital_gain', 'education_num', 'capital_loss', 'hours_week'] # Convert the type df_string = convertColumn(df_string, CONTI_FEATURES, FloatType()) # Check the dataset df_string.printSchema() root |-- age: float (nullable = true) |-- workclass: string (nullable = true) |-- fnlwgt: float (nullable = true) |-- education: string (nullable = true) |-- education_num: float (nullable = true) |-- marital: string (nullable = true) |-- occupation: string (nullable = true) |-- relationship: string (nullable = true) |-- race: string (nullable = true) |-- sex: string (nullable = true) |-- capital_gain: float (nullable = true) |-- capital_loss: float (nullable = true) |-- hours_week: float (nullable = true) |-- native_country: string (nullable = true) |-- label: string (nullable = true) from pyspark.ml.feature import StringIndexer #stringIndexer = StringIndexer(inputCol="label", outputCol="newlabel") #model = stringIndexer.fit(df) #df = model.transform(df) df.printSchema()
Wybierz kolumny
Możesz wybrać i wyświetlić wiersze z zaznaczeniem oraz nazwy funkcji. Poniżej wybrano wiek i fnlwgt.
df.select('age','fnlwgt').show(5)
+---+------+ |age|fnlwgt| +---+------+ | 39| 77516| | 50| 83311| | 38|215646| | 53|234721| | 28|338409| +---+------+ only showing top 5 rows
Licz według grup
Jeśli chcesz policzyć liczbę wystąpień według grupy, możesz to zrobić łańcuchowo:
- Grupuj według()
- liczyć()
razem. W PySpark w poniższym przykładzie liczysz liczbę wierszy według poziomu wykształcenia.
df.groupBy("education").count().sort("count",ascending=True).show()
+------------+-----+ | education|count| +------------+-----+ | Preschool| 51| | 1st-4th| 168| | 5th-6th| 333| | Doctorate| 413| | 12th| 433| | 9th| 514| | Prof-school| 576| | 7th-8th| 646| | 10th| 933| | Assoc-acdm| 1067| | 11th| 1175| | Assoc-voc| 1382| | Masters| 1723| | Bachelors| 5355| |Some-college| 7291| | HS-grad|10501| +------------+-----+
Opisz dane
Aby uzyskać podsumowanie statystyk danych, możesz użyć funkcji opisu (). Obliczy:
- liczyć
- oznaczać
- odchylenie standardowe
- min
- max
df.describe().show()
+-------+------------------+-----------+------------------+------------+-----------------+--------+----------------+------------+------------------+------+------------------+----------------+------------------+--------------+-----+ |summary| age| workclass| fnlwgt| education| education_num| marital| occupation|relationship| race| sex| capital_gain| capital_loss| hours_week|native_country|label| +-------+------------------+-----------+------------------+------------+-----------------+--------+----------------+------------+------------------+------+------------------+----------------+------------------+--------------+-----+ | count| 32561| 32561| 32561| 32561| 32561| 32561| 32561| 32561| 32561| 32561| 32561| 32561| 32561| 32561|32561| | mean| 38.58164675532078| null|189778.36651208502| null| 10.0806793403151| null| null| null| null| null|1077.6488437087312| 87.303829734959|40.437455852092995| null| null| | stddev|13.640432553581356| null|105549.97769702227| null|2.572720332067397| null| null| null| null| null| 7385.292084840354|402.960218649002|12.347428681731838| null| null| | min| 17| ?| 12285| 10th| 1|Divorced| ?| Husband|Amer-Indian-Eskimo|Female| 0| 0| 1| ?|<=50K| | max| 90|Without-pay| 1484705|Some-college| 16| Widowed|Transport-moving| Wife| White| Male| 99999| 4356| 99| Yugoslavia| >50K| +-------+------------------+-----------+------------------+------------+-----------------+--------+----------------+------------+------------------+------+------------------+----------------+------------------+--------------+-----+
Jeśli chcesz uzyskać statystykę podsumowującą tylko jedną kolumnę, dodaj nazwę kolumny wewnątrz funkcji opisu()
df.describe('capital_gain').show()
+-------+------------------+ |summary| capital_gain| +-------+------------------+ | count| 32561| | mean|1077.6488437087312| | stddev| 7385.292084840354| | min| 0| | max| 99999| +-------+------------------+
Obliczenia krzyżowe
W niektórych przypadkach może być interesujące zobaczenie statystyk opisowych między dwiema parami kolumn. Na przykład możesz policzyć liczbę osób z dochodem poniżej lub powyżej 50 tys. według poziomu wykształcenia. Ta operacja nazywa się tabelą krzyżową.
df.crosstab('age', 'label').sort("age_label").show()
+---------+-----+----+ |age_label|<=50K|>50K| +---------+-----+----+ | 17| 395| 0| | 18| 550| 0| | 19| 710| 2| | 20| 753| 0| | 21| 717| 3| | 22| 752| 13| | 23| 865| 12| | 24| 767| 31| | 25| 788| 53| | 26| 722| 63| | 27| 754| 81| | 28| 748| 119| | 29| 679| 134| | 30| 690| 171| | 31| 705| 183| | 32| 639| 189| | 33| 684| 191| | 34| 643| 243| | 35| 659| 217| | 36| 635| 263| +---------+-----+----+ only showing top 20 rows
Widać, że nikt w młodym wieku nie osiąga przychodów powyżej 50 tys.
Upuść kolumnę
Istnieją dwa intuicyjne API do upuszczania kolumn:
- drop(): Upuść kolumnę
- dropna(): Upuść NA
Poniżej upuszczasz kolumnę edukacja_num
df.drop('education_num').columns ['age', 'workclass', 'fnlwgt', 'education', 'marital', 'occupation', 'relationship', 'race', 'sex', 'capital_gain', 'capital_loss', 'hours_week', 'native_country', 'label']
Filtruj dane
Możesz użyć filter() aby zastosować statystyki opisowe w podzbiorze danych. Można na przykład policzyć liczbę osób powyżej 40. roku życia
df.filter(df.age > 40).count()
13443
Descript5 statystyk według grup
Na koniec można grupować dane według grup i obliczać operacje statystyczne, takie jak średnia.
df.groupby('marital').agg({'capital_gain': 'mean'}).show()
+--------------------+------------------+ | marital| avg(capital_gain)| +--------------------+------------------+ | Separated| 535.5687804878049| | Never-married|376.58831788823363| |Married-spouse-ab...| 653.9832535885167| | Divorced| 728.4148098131893| | Widowed| 571.0715005035247| | Married-AF-spouse| 432.6521739130435| | Married-civ-spouse|1764.8595085470085| +--------------------+------------------+
Krok 2) Wstępne przetwarzanie danych
Przetwarzanie danych to kluczowy etap uczenia maszynowego. Po usunięciu zbędnych danych uzyskasz kilka ważnych spostrzeżeń.
Na przykład wiesz, że wiek nie jest funkcją liniową z dochodem. Kiedy ludzie są młodzi, ich dochody są zwykle niższe niż w średnim wieku. Po przejściu na emeryturę gospodarstwo domowe korzysta z oszczędności, co oznacza spadek dochodów. Aby uchwycić ten wzór, możesz dodać kwadrat do funkcji wieku
Dodaj kwadrat wieku
Aby dodać nową funkcję należy:
- Wybierz kolumnę
- Zastosuj transformację i dodaj ją do ramki DataFrame
from pyspark.sql.functions import * # 1 Select the column age_square = df.select(col("age")**2) # 2 Apply the transformation and add it to the DataFrame df = df.withColumn("age_square", col("age")**2) df.printSchema() root |-- age: integer (nullable = true) |-- workclass: string (nullable = true) |-- fnlwgt: integer (nullable = true) |-- education: string (nullable = true) |-- education_num: integer (nullable = true) |-- marital: string (nullable = true) |-- occupation: string (nullable = true) |-- relationship: string (nullable = true) |-- race: string (nullable = true) |-- sex: string (nullable = true) |-- capital_gain: integer (nullable = true) |-- capital_loss: integer (nullable = true) |-- hours_week: integer (nullable = true) |-- native_country: string (nullable = true) |-- label: string (nullable = true) |-- age_square: double (nullable = true)
Możesz zobaczyć, że age_square został pomyślnie dodany do ramki danych. Możesz zmienić kolejność zmiennych za pomocą opcji Select. Poniżej wprowadzasz age_square zaraz po wieku.
COLUMNS = ['age', 'age_square', 'workclass', 'fnlwgt', 'education', 'education_num', 'marital', 'occupation', 'relationship', 'race', 'sex', 'capital_gain', 'capital_loss', 'hours_week', 'native_country', 'label'] df = df.select(COLUMNS) df.first()
Row(age=39, age_square=1521.0, workclass='State-gov', fnlwgt=77516, education='Bachelors', education_num=13, marital='Never-married', occupation='Adm-clerical', relationship='Not-in-family', race='White', sex='Male', capital_gain=2174, capital_loss=0, hours_week=40, native_country='United-States', label='<=50K')
Nie obejmuje Holandii i Holandii
Kiedy grupa w obrębie obiektu ma tylko jedną obserwację, nie wnosi ona żadnych informacji do modelu. Wręcz przeciwnie, może to prowadzić do błędu podczas sprawdzania krzyżowego.
Sprawdźmy pochodzenie gospodarstwa domowego
df.filter(df.native_country == 'Holand-Netherlands').count() df.groupby('native_country').agg({'native_country': 'count'}).sort(asc("count(native_country)")).show()
+--------------------+---------------------+ | native_country|count(native_country)| +--------------------+---------------------+ | Holand-Netherlands| 1| | Scotland| 12| | Hungary| 13| | Honduras| 13| |Outlying-US(Guam-...| 14| | Yugoslavia| 16| | Thailand| 18| | Laos| 18| | Cambodia| 19| | Trinadad&Tobago| 19| | Hong| 20| | Ireland| 24| | Ecuador| 28| | Greece| 29| | France| 29| | Peru| 31| | Nicaragua| 34| | Portugal| 37| | Iran| 43| | Haiti| 44| +--------------------+---------------------+ only showing top 20 rows
Funkcja native_country ma tylko jedno gospodarstwo domowe pochodzące z Holandii. Wykluczasz to.
df_remove = df.filter(df.native_country != 'Holand-Netherlands')
Krok 3) Zbuduj potok przetwarzania danych
Podobnie jak scikit-learn, PySpark ma interfejs API dla potoku.
Pipeline jest bardzo wygodny do utrzymania struktury danych. Wpychasz dane do pipeline. Wewnątrz pipeline wykonywane są różne operacje, a dane wyjściowe służą do zasilania algorytmu.
Na przykład jedna uniwersalna transformacja w uczeniu maszynowym polega na konwersji ciągu znaków na jeden gorący koder, tj. jedną kolumnę po grupie. Jeden gorący koder to zwykle macierz pełna zer.
Kroki transformacji danych są bardzo podobne do procesu scikit-learn. Musisz:
- Indeksuj ciąg znaków jako numeryczny
- Utwórz jeden gorący koder
- Przekształć dane
Zadanie to wykonują dwa interfejsy API: StringIndexer, OneHotEncoder
- Przede wszystkim wybierasz kolumnę z ciągiem znaków do indeksowania. inputCol to nazwa kolumny w zestawie danych. OutputCol to nowa nazwa nadana przekształconej kolumnie.
StringIndexer(inputCol="workclass", outputCol="workclass_encoded")
- Dopasuj dane i przekształć je
model = stringIndexer.fit(df)
`indexed = model.transform(df)``
- Utwórz kolumny wiadomości na podstawie grupy. Na przykład, jeśli w funkcji jest 10 grup, nowa macierz będzie miała 10 kolumn, po jednej dla każdej grupy.
OneHotEncoder(dropLast=False, inputCol="workclassencoded", outputCol="workclassvec")
### Example encoder from pyspark.ml.feature import StringIndexer, OneHotEncoder, VectorAssembler stringIndexer = StringIndexer(inputCol="workclass", outputCol="workclass_encoded") model = stringIndexer.fit(df) indexed = model.transform(df) encoder = OneHotEncoder(dropLast=False, inputCol="workclass_encoded", outputCol="workclass_vec") encoded = encoder.transform(indexed) encoded.show(2)
+---+----------+----------------+------+---------+-------------+------------------+---------------+-------------+-----+----+------------+------------+----------+--------------+-----+-----------------+-------------+ |age|age_square| workclass|fnlwgt|education|education_num| marital| occupation| relationship| race| sex|capital_gain|capital_loss|hours_week|native_country|label|workclass_encoded|workclass_vec| +---+----------+----------------+------+---------+-------------+------------------+---------------+-------------+-----+----+------------+------------+----------+--------------+-----+-----------------+-------------+ | 39| 1521.0| State-gov| 77516|Bachelors| 13| Never-married| Adm-clerical|Not-in-family|White|Male| 2174| 0| 40| United-States|<=50K| 4.0|(9,[4],[1.0])| | 50| 2500.0|Self-emp-not-inc| 83311|Bachelors| 13|Married-civ-spouse|Exec-managerial| Husband|White|Male| 0| 0| 13| United-States|<=50K| 1.0|(9,[1],[1.0])| +---+----------+----------------+------+---------+-------------+------------------+---------------+-------------+-----+----+------------+------------+----------+--------------+-----+-----------------+-------------+ only showing top 2 rows
Zbuduj rurociąg
Zbudujesz potok, aby przekonwertować wszystkie precyzyjne funkcje i dodać je do ostatecznego zestawu danych. Potok będzie miał cztery operacje, ale możesz dodać tyle operacji, ile chcesz.
- Zakoduj dane kategoryczne
- Indeksuj funkcję etykiety
- Dodaj zmienną ciągłą
- Złóż stopnie.
Każdy krok jest przechowywany na liście nazwanej etapami. Ta lista powie VectorAssemblerowi, jaką operację wykonać w potoku.
1. Zakoduj dane kategoryczne
Ten krok jest dokładnie taki sam jak przykład powyżej, z tą różnicą, że wykonujesz pętlę po wszystkich cechach kategorycznych.
from pyspark.ml import Pipeline from pyspark.ml.feature import OneHotEncoderEstimator CATE_FEATURES = ['workclass', 'education', 'marital', 'occupation', 'relationship', 'race', 'sex', 'native_country'] stages = [] # stages in our Pipeline for categoricalCol in CATE_FEATURES: stringIndexer = StringIndexer(inputCol=categoricalCol, outputCol=categoricalCol + "Index") encoder = OneHotEncoderEstimator(inputCols=[stringIndexer.getOutputCol()], outputCols=[categoricalCol + "classVec"]) stages += [stringIndexer, encoder]
Uwaga dotycząca API: OneHotEncoderEstimator został ponownie połączony z OneHotEncoder w Spark 3.0. Na Spark 3.x lub nowszy, zaimportuj OneHotEncoder i przekaż te same argumenty inputCols i outputCols; reszta pętli pozostaje niezmieniona.
2. Indeksuj element etykiety
Spark, podobnie jak wiele innych bibliotek, nie akceptuje wartości łańcuchowych dla etykiety. Konwertujesz funkcję etykiety za pomocą StringIndexer i dodajesz ją do etapów listy
# Convert label into label indices using the StringIndexer label_stringIdx = StringIndexer(inputCol="label", outputCol="newlabel") stages += [label_stringIdx]
3. Dodaj zmienną ciągłą
Parametr inputCols asemblera VectorAssembler to lista kolumn. Możesz utworzyć nową listę zawierającą wszystkie nowe kolumny. Poniższy kod wypełnia listę zakodowanymi cechami kategorialnymi i ciągłymi.
assemblerInputs = [c + "classVec" for c in CATE_FEATURES] + CONTI_FEATURES
4. Zmontuj stopnie.
Na koniec wykonujesz wszystkie kroki w VectorAssemblerze
assembler = VectorAssembler(inputCols=assemblerInputs, outputCol="features")stages += [assembler]
Teraz, gdy wszystkie kroki są gotowe, możesz wypychać dane do potoku.
# Create a Pipeline.
pipeline = Pipeline(stages=stages)
pipelineModel = pipeline.fit(df_remove)
model = pipelineModel.transform(df_remove)
Jeśli sprawdzisz nowy zbiór danych, zobaczysz, że zawiera on wszystkie funkcje, przekształcone i nie przekształcone. Interesuje Cię tylko nowa etykieta i funkcje. Cechy obejmują wszystkie przekształcone cechy i zmienne ciągłe.
model.take(1) [Row(age=39, age_square=1521.0, workclass='State-gov', fnlwgt=77516, education='Bachelors', education_num=13, marital='Never-married', occupation='Adm-clerical', relationship='Not-in-family', race='White', sex='Male', capital_gain=2174, capital_loss=0, hours_week=40, native_country='United-States', label='<=50K', workclassIndex=4.0, workclassclassVec=SparseVector(8, {4: 1.0}), educationIndex=2.0, educationclassVec=SparseVector(15, {2: 1.0}), maritalIndex=1.0, maritalclassVec=SparseVector(6, {1: 1.0}), occupationIndex=3.0, occupationclassVec=SparseVector(14, {3: 1.0}), relationshipIndex=1.0, relationshipclassVec=SparseVector(5, {1: 1.0}), raceIndex=0.0, raceclassVec=SparseVector(4, {0: 1.0}), sexIndex=0.0, sexclassVec=SparseVector(1, {0: 1.0}), native_countryIndex=0.0, native_countryclassVec=SparseVector(40, {0: 1.0}), newlabel=0.0, features=SparseVector(99, {4: 1.0, 10: 1.0, 24: 1.0, 32: 1.0, 44: 1.0, 48: 1.0, 52: 1.0, 53: 1.0, 93: 39.0, 94: 77516.0, 95: 2174.0, 96: 13.0, 98: 40.0}))]
Krok 4) Zbuduj klasyfikator: logistyczny
Aby przyspieszyć obliczenia, konwertujesz model na ramkę danych.
Musisz wybrać nową etykietę i funkcje z modelu za pomocą mapy.
from pyspark.ml.linalg import DenseVector input_data = model.rdd.map(lambda x: (x["newlabel"], DenseVector(x["features"])))
Można już tworzyć dane pociągu w postaci ramki DataFrame. Używasz sqlContext
df_train = sqlContext.createDataFrame(input_data, ["label", "features"])
Sprawdź drugi rząd
df_train.show(2)
+-----+--------------------+ |label| features| +-----+--------------------+ | 0.0|[0.0,0.0,0.0,0.0,...| | 0.0|[0.0,1.0,0.0,0.0,...| +-----+--------------------+ only showing top 2 rows
Utwórz zestaw pociągowy/testowy
Podzieliłeś zbiór danych 80/20 za pomocą randomSplit.
# Split the data into train and test sets
train_data, test_data = df_train.randomSplit([.8,.2],seed=1234)
Policzmy, ile osób ma dochody poniżej/powyżej 50 tys. zarówno w zbiorze treningowym, jak i testowym
train_data.groupby('label').agg({'label': 'count'}).show()
+-----+------------+ |label|count(label)| +-----+------------+ | 0.0| 19698| | 1.0| 6263| +-----+------------+
test_data.groupby('label').agg({'label': 'count'}).show()
+-----+------------+ |label|count(label)| +-----+------------+ | 0.0| 5021| | 1.0| 1578| +-----+------------+
Zbuduj regresor logistyczny
Na koniec, ale nie mniej ważne, możesz zbudować klasyfikator. PySpark ma API o nazwie LogisticRegression służące do wykonywania regresji logistycznej.
Inicjujesz lr, wskazując kolumnę etykiety i kolumny funkcji. Ustawiasz maksymalnie 10 iteracji i dodajesz parametr regularyzacji o wartości 0.3. Pamiętaj, że w następnej sekcji do dostrojenia modelu użyjesz sprawdzania krzyżowego z siatką parametrów
# Import `LinearRegression` from pyspark.ml.classification import LogisticRegression # Initialize `lr` lr = LogisticRegression(labelCol="label", featuresCol="features", maxIter=10, regParam=0.3) # Fit the data to the model linearModel = lr.fit(train_data)
#Możesz zobaczyć współczynniki z regresji
# Print the coefficients and intercept for logistic regression print("Coefficients: " + str(linearModel.coefficients)) print("Intercept: " + str(linearModel.intercept))
Coefficients: [-0.0678914665262,-0.153425526813,-0.0706009536407,-0.164057586562,-0.120655298528,0.162922330862,0.149176870438,-0.626836362611,-0.193483661541,-0.0782269980838,0.222667203836,0.399571096381,-0.0222024341804,-0.311925857859,-0.0434497788688,-0.306007744328,-0.41318209688,0.547937504247,-0.395837350854,-0.23166535958,0.618743906733,-0.344088614546,-0.385266881369,0.317324463006,-0.350518889186,-0.201335923138,-0.232878560088,-0.13349278865,-0.119760542498,0.17500602491,-0.0480968101118,0.288484253943,-0.116314616745,0.0524163478063,-0.300952624551,-0.22046421474,-0.16557996579,-0.114676231939,-0.311966431453,-0.344226119233,0.105530129507,0.152243047814,-0.292774545497,0.263628334433,-0.199951374076,-0.30329422583,-0.231087515178,0.418918551,-0.0565930184279,-0.177818073048,-0.0733236680663,-0.267972912252,0.168491215697,-0.12181255723,-0.385648075442,-0.202101794517,0.0469791640782,-0.00842850210625,-0.00373211448629,-0.259296141281,-0.309896554133,-0.168434409756,-0.11048086026,0.0280647963877,-0.204187030092,-0.414392623536,-0.252806580669,0.143366465705,-0.516359222663,-0.435627370849,-0.301949286524,0.0878249035894,-0.210951740965,-0.621417928742,-0.099445190784,-0.232671473401,-0.1077745606,-0.360429419703,-0.420362959052,-0.379729467809,-0.395186242741,0.0826401853838,-0.280251589972,0.187313505214,-0.20295228799,-0.431177064626,0.149759018379,-0.107114299614,-0.319314858424,0.0028450133235,-0.651220387649,-0.327918792207,-0.143659581445,0.00691075160413,8.38517628783e-08,2.18856717378e-05,0.0266701216268,0.000231075966823,0.00893832698698] Intercept: -1.9884177974805692
Krok 5) Wytrenuj i oceń model
Aby wygenerować prognozę dla zestawu testowego,
Możesz użyć linearModel z transform() na test_data
# Make predictions on test data using the transform() method.
predictions = linearModel.transform(test_data)
Możesz wydrukować elementy w prognozach
predictions.printSchema() root |-- label: double (nullable = true) |-- features: vector (nullable = true) |-- rawPrediction: vector (nullable = true) |-- probability: vector (nullable = true) |-- prediction: double (nullable = false)
Interesuje Cię etykieta, przewidywanie i prawdopodobieństwo
selected = predictions.select("label", "prediction", "probability") selected.show(20)
+-----+----------+--------------------+ |label|prediction| probability| +-----+----------+--------------------+ | 0.0| 0.0|[0.91560704124179...| | 0.0| 0.0|[0.92812140213994...| | 0.0| 0.0|[0.92161406774159...| | 0.0| 0.0|[0.96222760777142...| | 0.0| 0.0|[0.66363283056957...| | 0.0| 0.0|[0.65571324475477...| | 0.0| 0.0|[0.73053376932829...| | 0.0| 1.0|[0.31265053873570...| | 0.0| 0.0|[0.80005907577390...| | 0.0| 0.0|[0.76482251301640...| | 0.0| 0.0|[0.84447301189069...| | 0.0| 0.0|[0.75691912026619...| | 0.0| 0.0|[0.60902504096722...| | 0.0| 0.0|[0.80799228385509...| | 0.0| 0.0|[0.87704364852567...| | 0.0| 0.0|[0.83817652582377...| | 0.0| 0.0|[0.79655423248500...| | 0.0| 0.0|[0.82712311232246...| | 0.0| 0.0|[0.81372823882016...| | 0.0| 0.0|[0.59687710752201...| +-----+----------+--------------------+ only showing top 20 rows
Oceń model
Aby zobaczyć, jak dobrze (lub źle) działa model, należy przyjrzeć się metryce dokładności. Obecnie nie ma interfejsu API umożliwiającego obliczenie miary dokładności Spark. Wartością domyślną jest ROC, krzywa charakterystyki działania odbiornika. Jest to inna metryka, która uwzględnia współczynnik fałszywych wyników dodatnich.
Zanim spojrzysz na ROC, skonstruujmy miarę dokładności. Jesteś bardziej zaznajomiony z tym wskaźnikiem. Miarą dokładności jest suma poprawnych przewidywań na podstawie całkowitej liczby obserwacji.
Tworzysz DataFrame z etykietą i „prediction.
cm = predictions.select("label", "prediction")
Numer klasy możesz sprawdzić na etykiecie oraz w przewidywaniu
cm.groupby('label').agg({'label': 'count'}).show()
+-----+------------+ |label|count(label)| +-----+------------+ | 0.0| 5021| | 1.0| 1578| +-----+------------+
cm.groupby('prediction').agg({'prediction': 'count'}).show()
+----------+-----------------+ |prediction|count(prediction)| +----------+-----------------+ | 0.0| 5982| | 1.0| 617| +----------+-----------------+
Przykładowo w zbiorze testowym znajduje się 1578 gospodarstw domowych o dochodach powyżej 50 tys. i 5021 poniżej. Klasyfikator przewidział natomiast 617 gospodarstw domowych o dochodach powyżej 50 tys.
Dokładność można obliczyć, obliczając liczbę, gdy etykiety są poprawnie sklasyfikowane w całkowitej liczbie wierszy.
cm.filter(cm.label == cm.prediction).count() / cm.count()
0.8237611759357478
Możesz wszystko złożyć w całość i napisać funkcję obliczającą dokładność.
def accuracy_m(model): predictions = model.transform(test_data) cm = predictions.select("label", "prediction") acc = cm.filter(cm.label == cm.prediction).count() / cm.count() print("Model accuracy: %.3f%%" % (acc * 100)) accuracy_m(model = linearModel) Model accuracy: 82.376%
Wskaźniki ROC
Moduł BinaryClassificationEvaluator zawiera miary ROC. Odbiornik Operakrzywa charakterystyczna jest kolejnym powszechnym narzędziem używanym w klasyfikacji binarnej. Jest bardzo podobna do krzywej precyzji/przypomnienia, ale zamiast wykreślać precyzję w funkcji przypominania, krzywa ROC pokazuje prawdziwie dodatni współczynnik (tj. przypominanie) w porównaniu z fałszywie dodatnim współczynnikiem. Odsetek wyników fałszywie pozytywnych to stosunek przypadków negatywnych, które zostały błędnie sklasyfikowane jako pozytywne. Jest ona równa jeden minus rzeczywista stopa ujemna. Prawdziwie ujemna stopa nazywana jest również specyficznością. Stąd krzywa ROC przedstawia czułość (przypominanie) w funkcji 1 – swoistość
### Use ROC from pyspark.ml.evaluation import BinaryClassificationEvaluator # Evaluate model evaluator = BinaryClassificationEvaluator(rawPredictionCol="rawPrediction") print(evaluator.evaluate(predictions)) print(evaluator.getMetricName())
0.8940481662695192obszarPodROC
print(evaluator.evaluate(predictions))
0.8940481662695192
Krok 6) Dostosuj hiperparametr
Na koniec, ale nie mniej ważne, możesz dostroić hiperparametry. Podobnie jak w scikit-learn, tworzysz siatkę parametrów i dodajesz parametry, które chcesz dostroić.
Aby skrócić czas obliczeń, parametr regularyzacji dostraja się tylko za pomocą tylko dwóch wartości.
from pyspark.ml.tuning import ParamGridBuilder, CrossValidator # Create ParamGrid for Cross Validation paramGrid = (ParamGridBuilder() .addGrid(lr.regParam, [0.01, 0.5]) .build())
Na koniec oceniasz model, stosując metodę walidacji krzyżowej z 5-krotnym testem. Trening trwa około 16 minut.
from time import * start_time = time() # Create 5-fold CrossValidator cv = CrossValidator(estimator=lr, estimatorParamMaps=paramGrid, evaluator=evaluator, numFolds=5) # Run cross validations cvModel = cv.fit(train_data) # likely take a fair amount of time end_time = time() elapsed_time = end_time - start_time print("Time to train model: %.3f seconds" % elapsed_time)
Czas wytrenowania modelu: 978.807 sekundy
Najlepszy hiperparametr regularyzacji wynosi 0.01, z dokładnością 85.316 procent.
accuracy_m(model = cvModel) Model accuracy: 85.316%
Możesz byćtraczalecany parametr poprzez połączenie cvModel.bestModel z extractParamMap()
bestModel = cvModel.bestModel bestModel.extractParamMap()
{Param(parent='LogisticRegression_4d8f8ce4d6a02d8c29a0', name='aggregationDepth', doc='suggested depth for treeAggregate (>= 2)'): 2,
Param(parent='LogisticRegression_4d8f8ce4d6a02d8c29a0', name='elasticNetParam', doc='the ElasticNet mixing parameter, in range [0, 1]. For alpha = 0, the penalty is an L2 penalty. For alpha = 1, it is an L1 penalty'): 0.0,
Param(parent='LogisticRegression_4d8f8ce4d6a02d8c29a0', name='family', doc='The name of family which is a description of the label distribution to be used in the model. Supported options: auto, binomial, multinomial.'): 'auto',
Param(parent='LogisticRegression_4d8f8ce4d6a02d8c29a0', name='featuresCol', doc='features column name'): 'features',
Param(parent='LogisticRegression_4d8f8ce4d6a02d8c29a0', name='fitIntercept', doc='whether to fit an intercept term'): True,
Param(parent='LogisticRegression_4d8f8ce4d6a02d8c29a0', name='labelCol', doc='label column name'): 'label',
Param(parent='LogisticRegression_4d8f8ce4d6a02d8c29a0', name='maxIter', doc='maximum number of iterations (>= 0)'): 10,
Param(parent='LogisticRegression_4d8f8ce4d6a02d8c29a0', name='predictionCol', doc='prediction column name'): 'prediction',
Param(parent='LogisticRegression_4d8f8ce4d6a02d8c29a0', name='probabilityCol', doc='Column name for predicted class conditional probabilities. Note: Not all models output well-calibrated probability estimates! These probabilities should be treated as confidences, not precise probabilities'): 'probability',
Param(parent='LogisticRegression_4d8f8ce4d6a02d8c29a0', name='rawPredictionCol', doc='raw prediction (a.k.a. confidence) column name'): 'rawPrediction',
Param(parent='LogisticRegression_4d8f8ce4d6a02d8c29a0', name='regParam', doc='regularization parameter (>= 0)'): 0.01,
Param(parent='LogisticRegression_4d8f8ce4d6a02d8c29a0', name='standardization', doc='whether to standardize the training features before fitting the model'): True,
Param(parent='LogisticRegression_4d8f8ce4d6a02d8c29a0', name='threshold', doc='threshold in binary classification prediction, in range [0, 1]'): 0.5,
Param(parent='LogisticRegression_4d8f8ce4d6a02d8c29a0', name='tol', doc='the convergence tolerance for iterative algorithms (>= 0)'): 1e-06}


