{ "cells": [ { "cell_type": "markdown", "id": "3ccaa5aa", "metadata": {}, "source": [ "# NEWS SENTIMENT ANALYSIS - ETL-Pipeline using KAFKA-HADOOP-SPARK " ] }, { "cell_type": "code", "execution_count": 1, "id": "cbde3506", "metadata": {}, "outputs": [], "source": [ "from pyspark.ml import Pipeline\n", "from pyspark.ml.classification import RandomForestClassifier\n", "from pyspark.ml.evaluation import MulticlassClassificationEvaluator\n", "from pyspark.ml.feature import StopWordsRemover, Tokenizer, Word2Vec\n", "from pyspark.sql import SparkSession\n", "from pyspark.sql.functions import lower, when\n", "import json" ] }, { "cell_type": "code", "execution_count": 2, "id": "03ae1824", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "23/12/22 05:55:10 WARN NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable\n", "Using Spark's default log4j profile: org/apache/spark/log4j-defaults.properties\n", "Setting default log level to \"WARN\".\n", "To adjust logging level use sc.setLogLevel(newLevel). For SparkR, use setLogLevel(newLevel).\n" ] }, { "data": { "text/html": [ "\n", "
\n", "

SparkSession - in-memory

\n", " \n", "
\n", "

SparkContext

\n", "\n", "

Spark UI

\n", "\n", "
\n", "
Version
\n", "
v3.0.0
\n", "
Master
\n", "
local[*]
\n", "
AppName
\n", "
News Sentiment analysis
\n", "
\n", "
\n", " \n", "
\n", " " ], "text/plain": [ "" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# spark = SparkSession.builder.master(\"spark://localhost:7077\").appName(\"News Sentiment analysis\").getOrCreate()\n", "spark = SparkSession.builder.master(\"local[*]\").appName(\"News Sentiment analysis\").getOrCreate()\n", "spark" ] }, { "cell_type": "markdown", "id": "6a76e45e", "metadata": {}, "source": [ "## Load data from HDFS" ] }, { "cell_type": "code", "execution_count": 3, "id": "7e8a1d16", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ " \r" ] } ], "source": [ "hdfsPath = \"hdfs://namenode:9000/user/spark/news_data_articles.txt\"\n", "df = spark.read.json(hdfsPath)" ] }, { "cell_type": "code", "execution_count": 4, "id": "0bbcb94e", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "+-------+--------------------+--------------------+-------------------+--------------------+--------------------+--------------------+--------------------+\n", "| author| content| description| published_at| source| title| url| url_to_image|\n", "+-------+--------------------+--------------------+-------------------+--------------------+--------------------+--------------------+--------------------+\n", "|bbcnews|Thirty years afte...|The BBC's Fergal ...|2023-12-03 22:21:04|[bbc-news, BBC News]|South Africa: The...|https://www.bbc.c...|https://ichef.bbc...|\n", "|bbcnews|South Florida. A ...|The Grand Theft A...|2023-12-10 00:56:54|[bbc-news, BBC News]|Grand Theft Auto ...|https://www.bbc.c...|https://ichef.bbc...|\n", "|bbcnews|The families of t...|Police in Vermont...|2023-11-27 00:31:15|[bbc-news, BBC News]|Vermont: Three Pa...|https://www.bbc.c...|https://ichef.bbc...|\n", "|bbcnews|Homosexuality sho...|Cardinal Peter Tu...|2023-11-27 12:59:02|[bbc-news, BBC News]|Ghana Cardinal Pe...|https://www.bbc.c...|https://ichef.bbc...|\n", "|bbcnews|A key political a...|A two-year-old ta...|2023-11-23 06:00:31|[bbc-news, BBC News]|Missing Ukrainian...|https://www.bbc.c...|https://ichef.bbc...|\n", "|bbcnews|At the end of the...|Even when the war...|2023-12-09 09:48:23|[bbc-news, BBC News]|Israel-Gaza: The ...|https://www.bbc.c...|https://ichef.bbc...|\n", "|bbcnews|A manhunt is unde...|A manhunt is unde...|2023-12-11 13:10:39|[bbc-news, BBC News]|Switzerland manhu...|https://www.bbc.c...|https://ichef.bbc...|\n", "|bbcnews|It's all rather s...|Karin Kneissl dan...|2023-12-07 06:01:28|[bbc-news, BBC News]|Karin Kneissl, th...|https://www.bbc.c...|https://ichef.bbc...|\n", "|bbcnews|Russian President...|The Russian leade...|2023-12-06 12:56:45|[bbc-news, BBC News]|Putin lands in UA...|https://www.bbc.c...|https://ichef.bbc...|\n", "|bbcnews|Serbians are voti...|The ruling party ...|2023-12-17 13:17:45|[bbc-news, BBC News]|Serbians head to ...|https://www.bbc.c...|https://ichef.bbc...|\n", "|bbcnews|Police in Mexico ...|The victims were ...|2023-12-18 12:51:22|[bbc-news, BBC News]|Mexico violence: ...|https://www.bbc.c...|https://ichef.bbc...|\n", "|bbcnews|A homeless man mo...|When a drifter mo...|2023-11-26 01:11:32|[bbc-news, BBC News]|The homeless hand...|https://www.bbc.c...|https://ichef.bbc...|\n", "|bbcnews|It was, perhaps, ...|One man fined €40...|2023-11-27 17:41:30|[bbc-news, BBC News]|Slovenia Covid: T...|https://www.bbc.c...|https://ichef.bbc...|\n", "|bbcnews|Ukraine has launc...|Kyiv investigates...|2023-12-03 16:03:56|[bbc-news, BBC News]|Ukraine war: Russ...|https://www.bbc.c...|https://ichef.bbc...|\n", "|bbcnews|When New Zealand'...|The model for an ...|2023-12-11 00:26:33|[bbc-news, BBC News]|New Zealand smoki...|https://www.bbc.c...|https://ichef.bbc...|\n", "|Unknown|Students are bein...|Doctors have been...|2023-11-20 06:15:13|[bbc-news, BBC News]|Knife crime: 'We'...|https://www.bbc.c...|https://ichef.bbc...|\n", "|bbcnews|The murder of a y...|A vigil for healt...|2023-12-06 14:53:29|[bbc-news, BBC News]|Lurgan murder: Od...|https://www.bbc.c...|https://ichef.bbc...|\n", "|bbcnews|Super-strength st...|Synthetic opioids...|2023-12-11 00:44:28|[bbc-news, BBC News]|Street drugs stro...|https://www.bbc.c...|https://ichef.bbc...|\n", "|bbcnews|Michelle Mone say...|PPE Medpro is bei...|2023-12-10 13:15:27|[bbc-news, BBC News]|Tory peer Michell...|https://www.bbc.c...|https://ichef.bbc...|\n", "|bbcnews|All 221 Republica...|Republicans retur...|2023-12-15 18:47:13|[bbc-news, BBC News]|Biden impeachment...|https://www.bbc.c...|https://ichef.bbc...|\n", "+-------+--------------------+--------------------+-------------------+--------------------+--------------------+--------------------+--------------------+\n", "only showing top 20 rows\n", "\n" ] } ], "source": [ "df.show()" ] }, { "cell_type": "markdown", "id": "91492eec", "metadata": {}, "source": [ "# Data Preparation" ] }, { "cell_type": "code", "execution_count": 5, "id": "5404d2be", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "+-----+-----+\n", "|label|count|\n", "+-----+-----+\n", "| 1| 65|\n", "| 0| 546|\n", "+-----+-----+\n", "\n" ] } ], "source": [ "labeled_data = df.withColumn(\"label\", when(lower(df[\"description\"]).contains(\"crime\") |\n", " lower(df[\"description\"]).contains(\"murder\") |\n", " lower(df[\"description\"]).contains(\"robbery\"), 1).otherwise(0))\n", "labeled_data.groupBy(\"label\").count().show()" ] }, { "cell_type": "markdown", "id": "f27a8072", "metadata": {}, "source": [ "### Define a function to convert text to lowercase and tokenize it" ] }, { "cell_type": "code", "execution_count": 6, "id": "fd574468", "metadata": {}, "outputs": [], "source": [ "def tokenize_text(df):\n", " tokenizer = Tokenizer(inputCol=\"description\", outputCol=\"words\")\n", " return tokenizer.transform(df)" ] }, { "cell_type": "code", "execution_count": 7, "id": "9605eb57", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "+-------+--------------------+--------------------+-------------------+--------------------+--------------------+--------------------+--------------------+-----+--------------------+\n", "| author| content| description| published_at| source| title| url| url_to_image|label| words|\n", "+-------+--------------------+--------------------+-------------------+--------------------+--------------------+--------------------+--------------------+-----+--------------------+\n", "|bbcnews|Thirty years afte...|The BBC's Fergal ...|2023-12-03 22:21:04|[bbc-news, BBC News]|South Africa: The...|https://www.bbc.c...|https://ichef.bbc...| 0|[the, bbc's, ferg...|\n", "|bbcnews|South Florida. A ...|The Grand Theft A...|2023-12-10 00:56:54|[bbc-news, BBC News]|Grand Theft Auto ...|https://www.bbc.c...|https://ichef.bbc...| 0|[the, grand, thef...|\n", "|bbcnews|The families of t...|Police in Vermont...|2023-11-27 00:31:15|[bbc-news, BBC News]|Vermont: Three Pa...|https://www.bbc.c...|https://ichef.bbc...| 0|[police, in, verm...|\n", "|bbcnews|Homosexuality sho...|Cardinal Peter Tu...|2023-11-27 12:59:02|[bbc-news, BBC News]|Ghana Cardinal Pe...|https://www.bbc.c...|https://ichef.bbc...| 0|[cardinal, peter,...|\n", "|bbcnews|A key political a...|A two-year-old ta...|2023-11-23 06:00:31|[bbc-news, BBC News]|Missing Ukrainian...|https://www.bbc.c...|https://ichef.bbc...| 0|[a, two-year-old,...|\n", "|bbcnews|At the end of the...|Even when the war...|2023-12-09 09:48:23|[bbc-news, BBC News]|Israel-Gaza: The ...|https://www.bbc.c...|https://ichef.bbc...| 0|[even, when, the,...|\n", "|bbcnews|A manhunt is unde...|A manhunt is unde...|2023-12-11 13:10:39|[bbc-news, BBC News]|Switzerland manhu...|https://www.bbc.c...|https://ichef.bbc...| 0|[a, manhunt, is, ...|\n", "|bbcnews|It's all rather s...|Karin Kneissl dan...|2023-12-07 06:01:28|[bbc-news, BBC News]|Karin Kneissl, th...|https://www.bbc.c...|https://ichef.bbc...| 0|[karin, kneissl, ...|\n", "|bbcnews|Russian President...|The Russian leade...|2023-12-06 12:56:45|[bbc-news, BBC News]|Putin lands in UA...|https://www.bbc.c...|https://ichef.bbc...| 0|[the, russian, le...|\n", "|bbcnews|Serbians are voti...|The ruling party ...|2023-12-17 13:17:45|[bbc-news, BBC News]|Serbians head to ...|https://www.bbc.c...|https://ichef.bbc...| 0|[the, ruling, par...|\n", "|bbcnews|Police in Mexico ...|The victims were ...|2023-12-18 12:51:22|[bbc-news, BBC News]|Mexico violence: ...|https://www.bbc.c...|https://ichef.bbc...| 0|[the, victims, we...|\n", "|bbcnews|A homeless man mo...|When a drifter mo...|2023-11-26 01:11:32|[bbc-news, BBC News]|The homeless hand...|https://www.bbc.c...|https://ichef.bbc...| 0|[when, a, drifter...|\n", "|bbcnews|It was, perhaps, ...|One man fined €40...|2023-11-27 17:41:30|[bbc-news, BBC News]|Slovenia Covid: T...|https://www.bbc.c...|https://ichef.bbc...| 0|[one, man, fined,...|\n", "|bbcnews|Ukraine has launc...|Kyiv investigates...|2023-12-03 16:03:56|[bbc-news, BBC News]|Ukraine war: Russ...|https://www.bbc.c...|https://ichef.bbc...| 0|[kyiv, investigat...|\n", "|bbcnews|When New Zealand'...|The model for an ...|2023-12-11 00:26:33|[bbc-news, BBC News]|New Zealand smoki...|https://www.bbc.c...|https://ichef.bbc...| 0|[the, model, for,...|\n", "|Unknown|Students are bein...|Doctors have been...|2023-11-20 06:15:13|[bbc-news, BBC News]|Knife crime: 'We'...|https://www.bbc.c...|https://ichef.bbc...| 0|[doctors, have, b...|\n", "|bbcnews|The murder of a y...|A vigil for healt...|2023-12-06 14:53:29|[bbc-news, BBC News]|Lurgan murder: Od...|https://www.bbc.c...|https://ichef.bbc...| 0|[a, vigil, for, h...|\n", "|bbcnews|Super-strength st...|Synthetic opioids...|2023-12-11 00:44:28|[bbc-news, BBC News]|Street drugs stro...|https://www.bbc.c...|https://ichef.bbc...| 1|[synthetic, opioi...|\n", "|bbcnews|Michelle Mone say...|PPE Medpro is bei...|2023-12-10 13:15:27|[bbc-news, BBC News]|Tory peer Michell...|https://www.bbc.c...|https://ichef.bbc...| 1|[ppe, medpro, is,...|\n", "|bbcnews|All 221 Republica...|Republicans retur...|2023-12-15 18:47:13|[bbc-news, BBC News]|Biden impeachment...|https://www.bbc.c...|https://ichef.bbc...| 0|[republicans, ret...|\n", "+-------+--------------------+--------------------+-------------------+--------------------+--------------------+--------------------+--------------------+-----+--------------------+\n", "only showing top 20 rows\n", "\n" ] } ], "source": [ "tokenizer = Tokenizer(inputCol=\"description\", outputCol=\"words\")\n", "tokenized_data = tokenize_text(labeled_data)\n", "tokenized_data.show()" ] }, { "cell_type": "markdown", "id": "dd9ea063", "metadata": {}, "source": [ "### Define the StopWordsRemover and Create the \"filteredWords\" column" ] }, { "cell_type": "code", "execution_count": 8, "id": "38decca9", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "+-------+--------------------+--------------------+-------------------+--------------------+--------------------+--------------------+--------------------+-----+--------------------+--------------------+\n", "| author| content| description| published_at| source| title| url| url_to_image|label| words| filteredWords|\n", "+-------+--------------------+--------------------+-------------------+--------------------+--------------------+--------------------+--------------------+-----+--------------------+--------------------+\n", "|bbcnews|Thirty years afte...|The BBC's Fergal ...|2023-12-03 22:21:04|[bbc-news, BBC News]|South Africa: The...|https://www.bbc.c...|https://ichef.bbc...| 0|[the, bbc's, ferg...|[bbc's, fergal, k...|\n", "|bbcnews|South Florida. A ...|The Grand Theft A...|2023-12-10 00:56:54|[bbc-news, BBC News]|Grand Theft Auto ...|https://www.bbc.c...|https://ichef.bbc...| 0|[the, grand, thef...|[grand, theft, au...|\n", "|bbcnews|The families of t...|Police in Vermont...|2023-11-27 00:31:15|[bbc-news, BBC News]|Vermont: Three Pa...|https://www.bbc.c...|https://ichef.bbc...| 0|[police, in, verm...|[police, vermont,...|\n", "|bbcnews|Homosexuality sho...|Cardinal Peter Tu...|2023-11-27 12:59:02|[bbc-news, BBC News]|Ghana Cardinal Pe...|https://www.bbc.c...|https://ichef.bbc...| 0|[cardinal, peter,...|[cardinal, peter,...|\n", "|bbcnews|A key political a...|A two-year-old ta...|2023-11-23 06:00:31|[bbc-news, BBC News]|Missing Ukrainian...|https://www.bbc.c...|https://ichef.bbc...| 0|[a, two-year-old,...|[two-year-old, ta...|\n", "|bbcnews|At the end of the...|Even when the war...|2023-12-09 09:48:23|[bbc-news, BBC News]|Israel-Gaza: The ...|https://www.bbc.c...|https://ichef.bbc...| 0|[even, when, the,...|[even, war, israe...|\n", "|bbcnews|A manhunt is unde...|A manhunt is unde...|2023-12-11 13:10:39|[bbc-news, BBC News]|Switzerland manhu...|https://www.bbc.c...|https://ichef.bbc...| 0|[a, manhunt, is, ...|[manhunt, way, su...|\n", "|bbcnews|It's all rather s...|Karin Kneissl dan...|2023-12-07 06:01:28|[bbc-news, BBC News]|Karin Kneissl, th...|https://www.bbc.c...|https://ichef.bbc...| 0|[karin, kneissl, ...|[karin, kneissl, ...|\n", "|bbcnews|Russian President...|The Russian leade...|2023-12-06 12:56:45|[bbc-news, BBC News]|Putin lands in UA...|https://www.bbc.c...|https://ichef.bbc...| 0|[the, russian, le...|[russian, leader,...|\n", "|bbcnews|Serbians are voti...|The ruling party ...|2023-12-17 13:17:45|[bbc-news, BBC News]|Serbians head to ...|https://www.bbc.c...|https://ichef.bbc...| 0|[the, ruling, par...|[ruling, party, f...|\n", "|bbcnews|Police in Mexico ...|The victims were ...|2023-12-18 12:51:22|[bbc-news, BBC News]|Mexico violence: ...|https://www.bbc.c...|https://ichef.bbc...| 0|[the, victims, we...|[victims, young, ...|\n", "|bbcnews|A homeless man mo...|When a drifter mo...|2023-11-26 01:11:32|[bbc-news, BBC News]|The homeless hand...|https://www.bbc.c...|https://ichef.bbc...| 0|[when, a, drifter...|[drifter, moves, ...|\n", "|bbcnews|It was, perhaps, ...|One man fined €40...|2023-11-27 17:41:30|[bbc-news, BBC News]|Slovenia Covid: T...|https://www.bbc.c...|https://ichef.bbc...| 0|[one, man, fined,...|[one, man, fined,...|\n", "|bbcnews|Ukraine has launc...|Kyiv investigates...|2023-12-03 16:03:56|[bbc-news, BBC News]|Ukraine war: Russ...|https://www.bbc.c...|https://ichef.bbc...| 0|[kyiv, investigat...|[kyiv, investigat...|\n", "|bbcnews|When New Zealand'...|The model for an ...|2023-12-11 00:26:33|[bbc-news, BBC News]|New Zealand smoki...|https://www.bbc.c...|https://ichef.bbc...| 0|[the, model, for,...|[model, end, toba...|\n", "|Unknown|Students are bein...|Doctors have been...|2023-11-20 06:15:13|[bbc-news, BBC News]|Knife crime: 'We'...|https://www.bbc.c...|https://ichef.bbc...| 0|[doctors, have, b...|[doctors, teachin...|\n", "|bbcnews|The murder of a y...|A vigil for healt...|2023-12-06 14:53:29|[bbc-news, BBC News]|Lurgan murder: Od...|https://www.bbc.c...|https://ichef.bbc...| 0|[a, vigil, for, h...|[vigil, healthcar...|\n", "|bbcnews|Super-strength st...|Synthetic opioids...|2023-12-11 00:44:28|[bbc-news, BBC News]|Street drugs stro...|https://www.bbc.c...|https://ichef.bbc...| 1|[synthetic, opioi...|[synthetic, opioi...|\n", "|bbcnews|Michelle Mone say...|PPE Medpro is bei...|2023-12-10 13:15:27|[bbc-news, BBC News]|Tory peer Michell...|https://www.bbc.c...|https://ichef.bbc...| 1|[ppe, medpro, is,...|[ppe, medpro, sue...|\n", "|bbcnews|All 221 Republica...|Republicans retur...|2023-12-15 18:47:13|[bbc-news, BBC News]|Biden impeachment...|https://www.bbc.c...|https://ichef.bbc...| 0|[republicans, ret...|[republicans, ret...|\n", "+-------+--------------------+--------------------+-------------------+--------------------+--------------------+--------------------+--------------------+-----+--------------------+--------------------+\n", "only showing top 20 rows\n", "\n" ] } ], "source": [ "remover = StopWordsRemover(inputCol=\"words\", outputCol=\"filteredWords\")\n", "filtered_data = remover.transform(tokenized_data)\n", "filtered_data.show()" ] }, { "cell_type": "markdown", "id": "8bbdfa86", "metadata": {}, "source": [ "### Create a Word2Vec model" ] }, { "cell_type": "code", "execution_count": 9, "id": "8829801e", "metadata": {}, "outputs": [], "source": [ "word2Vec = Word2Vec(inputCol=\"filteredWords\", outputCol=\"features\", vectorSize=100, minCount=0)" ] }, { "cell_type": "markdown", "id": "02aafcaa", "metadata": {}, "source": [ "# Model Training" ] }, { "cell_type": "markdown", "id": "0a735363", "metadata": {}, "source": [ "### Create a RandomForestClassifier" ] }, { "cell_type": "code", "execution_count": 10, "id": "00a0aa2b", "metadata": {}, "outputs": [], "source": [ "rf = RandomForestClassifier(labelCol=\"label\", featuresCol=\"features\", numTrees=10, rawPredictionCol=\"rawPrediction\")\n" ] }, { "cell_type": "markdown", "id": "dd99d22b", "metadata": {}, "source": [ "### Create a pipeline with the stages" ] }, { "cell_type": "code", "execution_count": 11, "id": "49b0a36a", "metadata": {}, "outputs": [], "source": [ "pipeline = Pipeline(stages=[tokenizer, remover, word2Vec, rf])" ] }, { "cell_type": "markdown", "id": "240a8496", "metadata": {}, "source": [ "### Split the data into training and testing sets" ] }, { "cell_type": "code", "execution_count": 12, "id": "5d821413", "metadata": {}, "outputs": [], "source": [ "training_data, test_data = labeled_data.randomSplit([0.7, 0.3], seed=12345)\n" ] }, { "cell_type": "markdown", "id": "1792eeea", "metadata": {}, "source": [ "### Train the model" ] }, { "cell_type": "code", "execution_count": 13, "id": "cf4f760e", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "23/12/22 05:55:25 WARN BLAS: Failed to load implementation from: com.github.fommil.netlib.NativeSystemBLAS\n", "23/12/22 05:55:25 WARN BLAS: Failed to load implementation from: com.github.fommil.netlib.NativeRefBLAS\n" ] } ], "source": [ "model = pipeline.fit(training_data)" ] }, { "cell_type": "markdown", "id": "a092e015", "metadata": {}, "source": [ "## Make predictions on the test set" ] }, { "cell_type": "code", "execution_count": 14, "id": "6a862c2d", "metadata": {}, "outputs": [], "source": [ "predictions = model.transform(test_data)" ] }, { "cell_type": "markdown", "id": "946ce7ed", "metadata": {}, "source": [ "## Evaluate the model" ] }, { "cell_type": "code", "execution_count": 15, "id": "51c34a39", "metadata": {}, "outputs": [], "source": [ "evaluator = MulticlassClassificationEvaluator(labelCol=\"label\", predictionCol=\"prediction\", metricName=\"accuracy\")" ] }, { "cell_type": "code", "execution_count": 16, "id": "1650a6fc", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.8806818181818182" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "accuracy = evaluator.evaluate(predictions)\n", "accuracy" ] }, { "cell_type": "markdown", "id": "c49b44b0", "metadata": {}, "source": [ "# Save the model" ] }, { "cell_type": "code", "execution_count": 17, "id": "1beb353f", "metadata": {}, "outputs": [], "source": [ "from datetime import datetime \n", "timestamp = datetime.now().strftime(\"%Y%m%d%H%M%S\")\n", "save_path=f\"hdfs://namenode:9000/user/spark/saved_models/news_sentiment_multi_classification_model_{timestamp}\"" ] }, { "cell_type": "code", "execution_count": 18, "id": "aa7cbdb3", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "23/12/22 05:55:30 WARN MemoryManager: Total allocation exceeds 95.00% (906,992,014 bytes) of heap memory\n", "Scaling row group sizes to 96.54% for 7 writers\n", "23/12/22 05:55:30 WARN MemoryManager: Total allocation exceeds 95.00% (906,992,014 bytes) of heap memory\n", "Scaling row group sizes to 84.47% for 8 writers\n", "23/12/22 05:55:30 WARN MemoryManager: Total allocation exceeds 95.00% (906,992,014 bytes) of heap memory\n", "Scaling row group sizes to 75.08% for 9 writers\n", "23/12/22 05:55:30 WARN MemoryManager: Total allocation exceeds 95.00% (906,992,014 bytes) of heap memory\n", "Scaling row group sizes to 67.58% for 10 writers\n", "23/12/22 05:55:30 WARN MemoryManager: Total allocation exceeds 95.00% (906,992,014 bytes) of heap memory\n", "Scaling row group sizes to 75.08% for 9 writers\n", "23/12/22 05:55:30 WARN MemoryManager: Total allocation exceeds 95.00% (906,992,014 bytes) of heap memory\n", "Scaling row group sizes to 84.47% for 8 writers\n", "23/12/22 05:55:30 WARN MemoryManager: Total allocation exceeds 95.00% (906,992,014 bytes) of heap memory\n", "Scaling row group sizes to 96.54% for 7 writers\n", "23/12/22 05:55:31 WARN MemoryManager: Total allocation exceeds 95.00% (906,992,014 bytes) of heap memory\n", "Scaling row group sizes to 96.54% for 7 writers\n", "23/12/22 05:55:31 WARN MemoryManager: Total allocation exceeds 95.00% (906,992,014 bytes) of heap memory\n", "Scaling row group sizes to 84.47% for 8 writers\n", "23/12/22 05:55:31 WARN MemoryManager: Total allocation exceeds 95.00% (906,992,014 bytes) of heap memory\n", "Scaling row group sizes to 75.08% for 9 writers\n", "23/12/22 05:55:31 WARN MemoryManager: Total allocation exceeds 95.00% (906,992,014 bytes) of heap memory\n", "Scaling row group sizes to 67.58% for 10 writers\n", "23/12/22 05:55:31 WARN MemoryManager: Total allocation exceeds 95.00% (906,992,014 bytes) of heap memory\n", "Scaling row group sizes to 61.43% for 11 writers\n", "23/12/22 05:55:31 WARN MemoryManager: Total allocation exceeds 95.00% (906,992,014 bytes) of heap memory\n", "Scaling row group sizes to 67.58% for 10 writers\n", "23/12/22 05:55:31 WARN MemoryManager: Total allocation exceeds 95.00% (906,992,014 bytes) of heap memory\n", "Scaling row group sizes to 75.08% for 9 writers\n", "23/12/22 05:55:31 WARN MemoryManager: Total allocation exceeds 95.00% (906,992,014 bytes) of heap memory\n", "Scaling row group sizes to 84.47% for 8 writers\n", "23/12/22 05:55:31 WARN MemoryManager: Total allocation exceeds 95.00% (906,992,014 bytes) of heap memory\n", "Scaling row group sizes to 96.54% for 7 writers\n" ] } ], "source": [ "model.save(save_path)" ] }, { "cell_type": "markdown", "id": "72dbcc43", "metadata": {}, "source": [ "# Load the model and predict the latest news result" ] }, { "cell_type": "code", "execution_count": 19, "id": "9c651520", "metadata": {}, "outputs": [], "source": [ "from pyspark.ml import PipelineModel" ] }, { "cell_type": "code", "execution_count": 20, "id": "245ce144", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ " \r" ] } ], "source": [ "loaded_model = PipelineModel.load(save_path)" ] }, { "cell_type": "code", "execution_count": 21, "id": "3fcf5e3e", "metadata": {}, "outputs": [], "source": [ "# Make predictions on new data\n", "hdfsPath = \"hdfs://namenode:9000/user/spark/news_data_articles.txt\"\n", "new_data = spark.read.json(hdfsPath)\n", "\n", "labeled_data = df.withColumn(\"label\", when(lower(df[\"description\"]).contains(\"crime\") |\n", " lower(df[\"description\"]).contains(\"murder\") |\n", " lower(df[\"description\"]).contains(\"robbery\"), 1).otherwise(0))\n", "new_predictions = loaded_model.transform(labeled_data)\n", "\n", "# Evaluate the predictions on new data (if ground truth labels are available)\n", "new_accuracy = evaluator.evaluate(new_predictions)" ] }, { "cell_type": "code", "execution_count": 22, "id": "2e77b736", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.9083469721767594" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "new_accuracy" ] }, { "cell_type": "markdown", "id": "a55f975a", "metadata": {}, "source": [ "# Post Predictions" ] }, { "cell_type": "markdown", "id": "40f161ab", "metadata": {}, "source": [ "### Evaluate the model using relevant metrics and visualization" ] }, { "cell_type": "code", "execution_count": 23, "id": "c52e90c0", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Precision: 0.0\n", "Recall: 0.0\n", "F1 Score: 0.0\n", "Accuracy: 0.8806818181818182\n" ] } ], "source": [ "from pyspark.mllib.evaluation import MulticlassMetrics\n", "\n", "prediction_and_label = predictions.select(\"prediction\", \"label\").rdd.map(lambda row: (float(row[\"prediction\"]), float(row[\"label\"])))\n", "\n", "# Create MulticlassMetrics object\n", "metrics = MulticlassMetrics(prediction_and_label)\n", "\n", "# Overall statistics\n", "print(f\"Precision: {metrics.precision(1.0)}\")\n", "print(f\"Recall: {metrics.recall(1.0)}\") \n", "print(f\"F1 Score: {metrics.fMeasure(1.0)}\") \n", "print(f\"Accuracy: {metrics.accuracy}\")\n", "\n", "\n", "# from pyspark.mllib.evaluation import BinaryClassificationMetrics\n", "# prediction_and_label = predictions.select(\"rawPrediction\", \"label\").rdd.map(lambda row: (float(row[\"rawPrediction\"][1]), float(row[\"label\"])))\n", "# metrics = BinaryClassificationMetrics(predictions_and_labels)\n", "# print(f\"Area under ROC: {metrics.areaUnderROC}\")\n", "# evaluator = MulticlassClassificationEvaluator(labelCol=\"label\", predictionCol=\"prediction\", metricName=\"accuracy\")" ] }, { "cell_type": "code", "execution_count": 24, "id": "3c703d40", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Requirement already satisfied: matplotlib in /usr/local/lib/python3.9/dist-packages (3.8.2)\n", "Requirement already satisfied: contourpy>=1.0.1 in /usr/local/lib/python3.9/dist-packages (from matplotlib) (1.2.0)\n", "Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.9/dist-packages (from matplotlib) (0.12.1)\n", "Requirement already satisfied: fonttools>=4.22.0 in /usr/local/lib/python3.9/dist-packages (from matplotlib) (4.47.0)\n", "Requirement already satisfied: kiwisolver>=1.3.1 in /usr/local/lib/python3.9/dist-packages (from matplotlib) (1.4.5)\n", "Requirement already satisfied: numpy<2,>=1.21 in /usr/local/lib/python3.9/dist-packages (from matplotlib) (1.26.2)\n", "Requirement already satisfied: packaging>=20.0 in /usr/local/lib/python3.9/dist-packages (from matplotlib) (23.2)\n", "Requirement already satisfied: pillow>=8 in /usr/local/lib/python3.9/dist-packages (from matplotlib) (10.1.0)\n", "Requirement already satisfied: pyparsing>=2.3.1 in /usr/local/lib/python3.9/dist-packages (from matplotlib) (3.1.1)\n", "Requirement already satisfied: python-dateutil>=2.7 in /usr/local/lib/python3.9/dist-packages (from matplotlib) (2.8.2)\n", "Requirement already satisfied: importlib-resources>=3.2.0 in /usr/local/lib/python3.9/dist-packages (from matplotlib) (6.1.1)\n", "Requirement already satisfied: zipp>=3.1.0 in /usr/local/lib/python3.9/dist-packages (from importlib-resources>=3.2.0->matplotlib) (3.17.0)\n", "Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.9/dist-packages (from python-dateutil>=2.7->matplotlib) (1.16.0)\n", "\u001b[33mWARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv\u001b[0m\u001b[33m\n", "\u001b[0mRequirement already satisfied: seaborn in /usr/local/lib/python3.9/dist-packages (0.13.0)\n", "Requirement already satisfied: numpy!=1.24.0,>=1.20 in /usr/local/lib/python3.9/dist-packages (from seaborn) (1.26.2)\n", "Requirement already satisfied: pandas>=1.2 in /usr/local/lib/python3.9/dist-packages (from seaborn) (2.1.4)\n", "Requirement already satisfied: matplotlib!=3.6.1,>=3.3 in /usr/local/lib/python3.9/dist-packages (from seaborn) (3.8.2)\n", "Requirement already satisfied: contourpy>=1.0.1 in /usr/local/lib/python3.9/dist-packages (from matplotlib!=3.6.1,>=3.3->seaborn) (1.2.0)\n", "Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.9/dist-packages (from matplotlib!=3.6.1,>=3.3->seaborn) (0.12.1)\n", "Requirement already satisfied: fonttools>=4.22.0 in /usr/local/lib/python3.9/dist-packages (from matplotlib!=3.6.1,>=3.3->seaborn) (4.47.0)\n", "Requirement already satisfied: kiwisolver>=1.3.1 in /usr/local/lib/python3.9/dist-packages (from matplotlib!=3.6.1,>=3.3->seaborn) (1.4.5)\n", "Requirement already satisfied: packaging>=20.0 in /usr/local/lib/python3.9/dist-packages (from matplotlib!=3.6.1,>=3.3->seaborn) (23.2)\n", "Requirement already satisfied: pillow>=8 in /usr/local/lib/python3.9/dist-packages (from matplotlib!=3.6.1,>=3.3->seaborn) (10.1.0)\n", "Requirement already satisfied: pyparsing>=2.3.1 in /usr/local/lib/python3.9/dist-packages (from matplotlib!=3.6.1,>=3.3->seaborn) (3.1.1)\n", "Requirement already satisfied: python-dateutil>=2.7 in /usr/local/lib/python3.9/dist-packages (from matplotlib!=3.6.1,>=3.3->seaborn) (2.8.2)\n", "Requirement already satisfied: importlib-resources>=3.2.0 in /usr/local/lib/python3.9/dist-packages (from matplotlib!=3.6.1,>=3.3->seaborn) (6.1.1)\n", "Requirement already satisfied: pytz>=2020.1 in /usr/local/lib/python3.9/dist-packages (from pandas>=1.2->seaborn) (2023.3.post1)\n", "Requirement already satisfied: tzdata>=2022.1 in /usr/local/lib/python3.9/dist-packages (from pandas>=1.2->seaborn) (2023.3)\n", "Requirement already satisfied: zipp>=3.1.0 in /usr/local/lib/python3.9/dist-packages (from importlib-resources>=3.2.0->matplotlib!=3.6.1,>=3.3->seaborn) (3.17.0)\n", "Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.9/dist-packages (from python-dateutil>=2.7->matplotlib!=3.6.1,>=3.3->seaborn) (1.16.0)\n", "\u001b[33mWARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv\u001b[0m\u001b[33m\n", "\u001b[0mRequirement already satisfied: scikit-learn in /usr/local/lib/python3.9/dist-packages (1.3.2)\n", "Requirement already satisfied: numpy<2.0,>=1.17.3 in /usr/local/lib/python3.9/dist-packages (from scikit-learn) (1.26.2)\n", "Requirement already satisfied: scipy>=1.5.0 in /usr/local/lib/python3.9/dist-packages (from scikit-learn) (1.11.4)\n", "Requirement already satisfied: joblib>=1.1.1 in /usr/local/lib/python3.9/dist-packages (from scikit-learn) (1.3.2)\n", "Requirement already satisfied: threadpoolctl>=2.0.0 in /usr/local/lib/python3.9/dist-packages (from scikit-learn) (3.2.0)\n", "\u001b[33mWARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv\u001b[0m\u001b[33m\n", "\u001b[0m" ] } ], "source": [ "!pip install matplotlib\n", "!pip install seaborn\n", "!pip install scikit-learn\n", "import matplotlib.pyplot as plt\n", "import seaborn as sns\n", "from sklearn.metrics import confusion_matrix,roc_curve" ] }, { "cell_type": "markdown", "id": "c853d69c", "metadata": {}, "source": [ "### Confusion Matrix\n", " Examine the confusion matrix to understand the distribution of true positives, true negatives, false positives, and false negatives." ] }, { "cell_type": "code", "execution_count": 25, "id": "c36577f2", "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAhsAAAHHCAYAAAAWM5p0AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8g+/7EAAAACXBIWXMAAA9hAAAPYQGoP6dpAAA6P0lEQVR4nO3deVxV5dr/8e9GZYMoIA4M5UBlzmkOEdlJTcopk7TM8hSaaYNaipnSybGBMkvDIarTUfNoc1JZWYYpWTiEUWZmTmll4Igk6hZh/f7w537OFjTQfbOB/Xk/r/V6xb3uvda1eB4fL6/rvte2WZZlCQAAwBAfTwcAAAAqN5INAABgFMkGAAAwimQDAAAYRbIBAACMItkAAABGkWwAAACjSDYAAIBRJBsAAMAokg3AoK1bt+rGG29UUFCQbDabUlJS3Hr9X3/9VTabTfPnz3frdSuyzp07q3Pnzp4OA8D/INlApbd9+3bdd999uuSSS+Tn56fAwEB17NhRL774oo4dO2b03nFxcdq4caOeeuopLVy4UO3btzd6v7I0aNAg2Ww2BQYGFvt73Lp1q2w2m2w2m6ZPn17q6+/Zs0eTJ09WZmamG6IF4ElVPR0AYNLHH3+s2267TXa7XXfffbdatmypEydOaPXq1Ro7dqw2bdqkV155xci9jx07pvT0dP3rX//SiBEjjNyjYcOGOnbsmKpVq2bk+n+natWqOnr0qD766CP179/f5dyiRYvk5+en48ePn9e19+zZoylTpqhRo0Zq06ZNiT/3+eefn9f9AJhDsoFKa+fOnRowYIAaNmyoFStWKDw83Hlu+PDh2rZtmz7++GNj99+3b58kKTg42Ng9bDab/Pz8jF3/79jtdnXs2FFvvPFGkWRj8eLF6tWrl957770yieXo0aOqXr26fH19y+R+AEqONgoqrWnTpunIkSN67bXXXBKN0y677DI9/PDDzp9PnjypJ554QpdeeqnsdrsaNWqkxx57TA6Hw+VzjRo10k033aTVq1frqquukp+fny655BK9/vrrzjmTJ09Ww4YNJUljx46VzWZTo0aNJJ1qP5z+7/81efJk2Ww2l7Hly5fr2muvVXBwsGrUqKEmTZrosccec54/25qNFStW6B//+IcCAgIUHBysPn36aPPmzcXeb9u2bRo0aJCCg4MVFBSkwYMH6+jRo2f/xZ7hzjvv1KeffqqcnBzn2Pr167V161bdeeedReYfPHhQjzzyiFq1aqUaNWooMDBQPXr00Pfff++cs3LlSnXo0EGSNHjwYGc75vRzdu7cWS1btlRGRoauu+46Va9e3fl7OXPNRlxcnPz8/Io8f7du3VSrVi3t2bOnxM8K4PyQbKDS+uijj3TJJZfommuuKdH8e++9VxMnTlTbtm01Y8YMderUSYmJiRowYECRudu2bdOtt96qG264Qc8//7xq1aqlQYMGadOmTZKkvn37asaMGZKkO+64QwsXLtTMmTNLFf+mTZt00003yeFwaOrUqXr++ed188036+uvvz7n57744gt169ZNe/fu1eTJkxUfH69vvvlGHTt21K+//lpkfv/+/fXXX38pMTFR/fv31/z58zVlypQSx9m3b1/ZbDa9//77zrHFixeradOmatu2bZH5O3bsUEpKim666Sa98MILGjt2rDZu3KhOnTo5/+Jv1qyZpk6dKkkaNmyYFi5cqIULF+q6665zXufAgQPq0aOH2rRpo5kzZ6pLly7Fxvfiiy+qbt26iouLU0FBgSTp5Zdf1ueff65Zs2YpIiKixM8K4DxZQCV0+PBhS5LVp0+fEs3PzMy0JFn33nuvy/gjjzxiSbJWrFjhHGvYsKElyUpLS3OO7d2717Lb7daYMWOcYzt37rQkWc8995zLNePi4qyGDRsWiWHSpEnW//6RnDFjhiXJ2rdv31njPn2PefPmOcfatGlj1atXzzpw4IBz7Pvvv7d8fHysu+++u8j97rnnHpdr3nLLLVbt2rXPes//fY6AgADLsizr1ltvtbp27WpZlmUVFBRYYWFh1pQpU4r9HRw/ftwqKCgo8hx2u92aOnWqc2z9+vVFnu20Tp06WZKs5OTkYs916tTJZeyzzz6zJFlPPvmktWPHDqtGjRpWbGzs3z4jAPegsoFKKTc3V5JUs2bNEs3/5JNPJEnx8fEu42PGjJGkIms7mjdvrn/84x/On+vWrasmTZpox44d5x3zmU6v9fjggw9UWFhYos/8+eefyszM1KBBgxQSEuIcv+KKK3TDDTc4n/N/3X///S4//+Mf/9CBAwecv8OSuPPOO7Vy5UplZWVpxYoVysrKKraFIp1a5+Hjc+r/9RQUFOjAgQPOFtGGDRtKfE+73a7BgweXaO6NN96o++67T1OnTlXfvn3l5+enl19+ucT3AnBhSDZQKQUGBkqS/vrrrxLN37Vrl3x8fHTZZZe5jIeFhSk4OFi7du1yGW/QoEGRa9SqVUuHDh06z4iLuv3229WxY0fde++9Cg0N1YABA/T222+fM/E4HWeTJk2KnGvWrJn279+vvLw8l/Ezn6VWrVqSVKpn6dmzp2rWrKm33npLixYtUocOHYr8Lk8rLCzUjBkz1LhxY9ntdtWpU0d169bVDz/8oMOHD5f4nhdddFGpFoNOnz5dISEhyszMVFJSkurVq1fizwK4MCQbqJQCAwMVERGhH3/8sVSfO3OB5tlUqVKl2HHLss77HqfXE5zm7++vtLQ0ffHFF7rrrrv0ww8/6Pbbb9cNN9xQZO6FuJBnOc1ut6tv375asGCBlixZctaqhiQ9/fTTio+P13XXXaf//ve/+uyzz7R8+XK1aNGixBUc6dTvpzS+++477d27V5K0cePGUn0WwIUh2UClddNNN2n79u1KT0//27kNGzZUYWGhtm7d6jKenZ2tnJwc584Sd6hVq5bLzo3TzqyeSJKPj4+6du2qF154QT/99JOeeuoprVixQl9++WWx1z4d55YtW4qc+/nnn1WnTh0FBARc2AOcxZ133qnvvvtOf/31V7GLak9799131aVLF7322msaMGCAbrzxRsXExBT5nZQ08SuJvLw8DR48WM2bN9ewYcM0bdo0rV+/3m3XB3BuJBuotB599FEFBATo3nvvVXZ2dpHz27dv14svvijpVBtAUpEdIy+88IIkqVevXm6L69JLL9Xhw4f1ww8/OMf+/PNPLVmyxGXewYMHi3z29MutztyOe1p4eLjatGmjBQsWuPzl/eOPP+rzzz93PqcJXbp00RNPPKHZs2crLCzsrPOqVKlSpGryzjvv6I8//nAZO50UFZeYlda4ceO0e/duLViwQC+88IIaNWqkuLi4s/4eAbgXL/VCpXXppZdq8eLFuv3229WsWTOXN4h+8803eueddzRo0CBJUuvWrRUXF6dXXnlFOTk56tSpk9atW6cFCxYoNjb2rNsqz8eAAQM0btw43XLLLXrooYd09OhRvfTSS7r88stdFkhOnTpVaWlp6tWrlxo2bKi9e/dq7ty5uvjii3Xttdee9frPPfecevTooejoaA0ZMkTHjh3TrFmzFBQUpMmTJ7vtOc7k4+Ojxx9//G/n3XTTTZo6daoGDx6sa665Rhs3btSiRYt0ySWXuMy79NJLFRwcrOTkZNWsWVMBAQGKiopSZGRkqeJasWKF5s6dq0mTJjm34s6bN0+dO3fWhAkTNG3atFJdD8B58PBuGMC4X375xRo6dKjVqFEjy9fX16pZs6bVsWNHa9asWdbx48ed8/Lz860pU6ZYkZGRVrVq1az69etbCQkJLnMs69TW1169ehW5z5lbLs+29dWyLOvzzz+3WrZsafn6+lpNmjSx/vvf/xbZ+pqammr16dPHioiIsHx9fa2IiAjrjjvusH755Zci9zhze+gXX3xhdezY0fL397cCAwOt3r17Wz/99JPLnNP3O3Nr7bx58yxJ1s6dO8/6O7Us162vZ3O2ra9jxoyxwsPDLX9/f6tjx45Wenp6sVtWP/jgA6t58+ZW1apVXZ6zU6dOVosWLYq95/9eJzc312rYsKHVtm1bKz8/32Xe6NGjLR8fHys9Pf2czwDgwtksqxSrwAAAAEqJNRsAAMAokg0AAGAUyQYAADCKZAMAABhFsgEAAIwi2QAAAEaRbAAAAKMq5RtE/a8c4ekQgHLp0PrZng4BKHf8yuBvQnf9vXTsu4r5Z5jKBgAAMKpSVjYAAChXbN79b3uSDQAATLPZPB2BR5FsAABgmpdXNrz76QEAgHFUNgAAMI02CgAAMIo2CgAAgDlUNgAAMI02CgAAMIo2CgAAgDlUNgAAMI02CgAAMIo2CgAAgDlUNgAAMI02CgAAMMrL2ygkGwAAmObllQ3vTrUAAIBxVDYAADCNNgoAADDKy5MN7356AABgHJUNAABM8/HuBaIkGwAAmEYbBQAAwBwqGwAAmObl79kg2QAAwDTaKAAAAOZQ2QAAwDTaKAAAwCgvb6OQbAAAYJqXVza8O9UCAADGkWwAAGCazcc9RymlpaWpd+/eioiIkM1mU0pKylnn3n///bLZbJo5c6bL+MGDBzVw4EAFBgYqODhYQ4YM0ZEjR0oVB8kGAACm2WzuOUopLy9PrVu31pw5c845b8mSJVqzZo0iIiKKnBs4cKA2bdqk5cuXa+nSpUpLS9OwYcNKFQdrNgAAqKR69OihHj16nHPOH3/8oZEjR+qzzz5Tr169XM5t3rxZy5Yt0/r169W+fXtJ0qxZs9SzZ09Nnz692OSkOFQ2AAAwzU1tFIfDodzcXJfD4XCcd1iFhYW66667NHbsWLVo0aLI+fT0dAUHBzsTDUmKiYmRj4+P1q5dW+L7kGwAAGCam9ooiYmJCgoKcjkSExPPO6xnn31WVatW1UMPPVTs+aysLNWrV89lrGrVqgoJCVFWVlaJ70MbBQCACiIhIUHx8fEuY3a7/byulZGRoRdffFEbNmyQzfDWXCobAACY5qY2it1uV2BgoMtxvsnGV199pb1796pBgwaqWrWqqlatql27dmnMmDFq1KiRJCksLEx79+51+dzJkyd18OBBhYWFlfheVDYAADCtHL5B9K677lJMTIzLWLdu3XTXXXdp8ODBkqTo6Gjl5OQoIyND7dq1kyStWLFChYWFioqKKvG9SDYAAKikjhw5om3btjl/3rlzpzIzMxUSEqIGDRqodu3aLvOrVaumsLAwNWnSRJLUrFkzde/eXUOHDlVycrLy8/M1YsQIDRgwoMQ7USSSDQAAzPPQ68q//fZbdenSxfnz6fUecXFxmj9/fomusWjRIo0YMUJdu3aVj4+P+vXrp6SkpFLFQbIBAIBpHmqjdO7cWZZllXj+r7/+WmQsJCREixcvvqA4SDYAADCNL2IDAAAwh8oGAACmlcPdKGWJZAMAANNoowAAAJhDZQMAAMNMvw68vCPZAADAMG9PNmijAAAAo6hsAABgmncXNkg2AAAwjTYKAACAQVQ2AAAwzNsrGyQbAAAYRrIBAACM8vZkgzUbAADAKCobAACY5t2FDZINAABMo40CAABgEJUNAAAM8/bKBskGAACGeXuyQRsFAAAYRWUDAADDvL2yQbIBAIBp3p1r0EYBAABmUdkAAMAw2igAAMAokg0AAGCUtycbrNkAAABGUdkAAMA07y5skGwAAGAabRQAAACDqGwAAGCYt1c2SDYAADDM25MN2igAAMAoKhsAABjm7ZUNkg0AAEzz7lyDNgoAAJVVWlqaevfurYiICNlsNqWkpDjP5efna9y4cWrVqpUCAgIUERGhu+++W3v27HG5xsGDBzVw4EAFBgYqODhYQ4YM0ZEjR0oVB8kGAACG2Ww2txyllZeXp9atW2vOnDlFzh09elQbNmzQhAkTtGHDBr3//vvasmWLbr75Zpd5AwcO1KZNm7R8+XItXbpUaWlpGjZsWOme37Isq9TRl3P+V47wdAhAuXRo/WxPhwCUO35lsKDg4gdT3HKd3+fGnvdnbTablixZotjYs19j/fr1uuqqq7Rr1y41aNBAmzdvVvPmzbV+/Xq1b99ekrRs2TL17NlTv//+uyIiIkp0byobAAAY5qnKRmkdPnxYNptNwcHBkqT09HQFBwc7Ew1JiomJkY+Pj9auXVvi67JAFACACsLhcMjhcLiM2e122e32C7728ePHNW7cON1xxx0KDAyUJGVlZalevXou86pWraqQkBBlZWWV+NpUNgAAMM3mniMxMVFBQUEuR2Ji4gWHl5+fr/79+8uyLL300ksXfL0zUdkAAMAwd7VAEhISFB8f7zJ2oVWN04nGrl27tGLFCmdVQ5LCwsK0d+9el/knT57UwYMHFRYWVuJ7kGwAAFBBuKtlctrpRGPr1q368ssvVbt2bZfz0dHRysnJUUZGhtq1aydJWrFihQoLCxUVFVXi+5BsoNQ6tr1Uo++OUdvmDRReN0j9R7+ij1b+4Dz/ypR/6q6br3b5zOdf/6Q+I+Y6f/754ylqGOH6f9QTkj7Q9HnLzQYPeNibixdpwbzXtH//Pl3epKnGPzZBra64wtNhwTBPvUH0yJEj2rZtm/PnnTt3KjMzUyEhIQoPD9ett96qDRs2aOnSpSooKHCuwwgJCZGvr6+aNWum7t27a+jQoUpOTlZ+fr5GjBihAQMGlHgnikSygfMQ4G/Xxl/+0OsfpOutF4rfa/3Z15t036T/On92nDhZZM6UuUs17/2vnT//lecoMgeoTJZ9+ommT0vU45OmqFWr1lq0cIEeuG+IPli6rMi/KFG5eCrZ+Pbbb9WlSxfnz6dbMHFxcZo8ebI+/PBDSVKbNm1cPvfll1+qc+fOkqRFixZpxIgR6tq1q3x8fNSvXz8lJSWVKg6SDZTa51//pM+//umcc06cOKnsA3+dc86RvON/OweoTBYumKe+t/ZX7C39JEmPT5qitLSVSnn/PQ0ZWrqXJAEl0blzZ53rdVoledVWSEiIFi9efEFxeDTZ2L9/v/7zn/8oPT3dWboJCwvTNddco0GDBqlu3bqeDA8X4B/tG2tXaqJyco9q5fpfNGXOUh08nOcyZ8zgGzV+aA/9lnVQb3/6rZIWfamCgkIPRQyYlX/ihDb/tElDht7nHPPx8dHVV1+jH77/zoORoSzwRWwesn79enXr1k3Vq1dXTEyMLr/8cklSdna2kpKS9Mwzz+izzz5zeZEIKobl32zWByu+169/HNAlF9fRlJG99cHsB9Qp7nkVFp7Koue+sUrfbf5Nh3LzdHXrSzR15M0Kqxukcc+/7+HoATMO5RxSQUFBkXZJ7dq1tXPnDg9FhTLj3bmG55KNkSNH6rbbblNycnKRjM+yLN1///0aOXKk0tPTz3md4l5wYhUWyOZTxe0xo2Te+SzD+d+btu3Rxq1/aPPSKbqufWOtXPeLJCnpvyucc37cukcn8k9q9r/u0ISkD3Uiv+j6DgBAxeWxl3p9//33Gj16dLGlJZvNptGjRyszM/Nvr1PcC05OZmf87edQdn7944D2HfpLl9Y/e1ts/cZfVa1aFTWMCCnDyICyUyu4lqpUqaIDBw64jB84cEB16tTxUFQoKxXldeWmeCzZCAsL07p16856ft26dQoNDf3b6yQkJOjw4cMuR9XQdu4MFRfoonrBqh0UoKz9uWed07rJxSooKNS+gywYReVUzddXzZq30No1/1etLSws1Nq16bqi9ZUejAxlwduTDY+1UR555BENGzZMGRkZ6tq1qzOxyM7OVmpqql599VVNnz79b69T3AtOaKGYFeDv61KlaHRRbV1x+UU6lHtUBw/n6V/39VRKaqay9ufqkvp19NTDsdr+234t/2azJCnqikh1aNlQq77dqr/yjuvqKyL17CP99MYn65Xz1zFPPRZg3F1xgzXhsXFq0aKlWra6Qv9duEDHjh1T7C19PR0aDKvAeYJbeCzZGD58uOrUqaMZM2Zo7ty5KigokCRVqVJF7dq10/z589W/f39PhYdzaNu8oT7/98POn6c9cmob38IP1+ihp99Sy8YXaWDvKAXX9Nef+w7ri/SfNXXuUudaDMeJfN3WrZ3+dX9P2atV1a97DmjWoi+VtHBFsfcDKovuPXrq0MGDmjs7Sfv371OTps009+V/qzZtFFRyNqskm2wNy8/P1/79+yVJderUUbVq1S7oev5XjnBHWEClc2j9bE+HAJQ7fmXwz+7GY5e55Tpbn+vuluuUtXLxUq9q1aopPDzc02EAAGCEt7dR+Ip5AABgVLmobAAAUJlV5J0k7kCyAQCAYV6ea9BGAQAAZlHZAADAMB8f7y5tkGwAAGAYbRQAAACDqGwAAGAYu1EAAIBRXp5rkGwAAGCat1c2WLMBAACMorIBAIBh3l7ZINkAAMAwL881aKMAAACzqGwAAGAYbRQAAGCUl+catFEAAIBZVDYAADCMNgoAADDKy3MN2igAAMAsKhsAABhGGwUAABjl5bkGyQYAAKZ5e2WDNRsAAMAoKhsAABjm5YUNkg0AAEyjjQIAAGAQlQ0AAAzz8sIGlQ0AAEyz2WxuOUorLS1NvXv3VkREhGw2m1JSUlzOW5aliRMnKjw8XP7+/oqJidHWrVtd5hw8eFADBw5UYGCggoODNWTIEB05cqRUcZBsAABQSeXl5al169aaM2dOseenTZumpKQkJScna+3atQoICFC3bt10/Phx55yBAwdq06ZNWr58uZYuXaq0tDQNGzasVHHQRgEAwDBPtVF69OihHj16FHvOsizNnDlTjz/+uPr06SNJev311xUaGqqUlBQNGDBAmzdv1rJly7R+/Xq1b99ekjRr1iz17NlT06dPV0RERInioLIBAIBh7mqjOBwO5ebmuhwOh+O8Ytq5c6eysrIUExPjHAsKClJUVJTS09MlSenp6QoODnYmGpIUExMjHx8frV27tsT3ItkAAKCCSExMVFBQkMuRmJh4XtfKysqSJIWGhrqMh4aGOs9lZWWpXr16LuerVq2qkJAQ55ySoI0CAIBh7nrPRkJCguLj413G7Ha7W65tEskGAACGuWvNht1ud1tyERYWJknKzs5WeHi4czw7O1tt2rRxztm7d6/L506ePKmDBw86P18StFEAADDMU1tfzyUyMlJhYWFKTU11juXm5mrt2rWKjo6WJEVHRysnJ0cZGRnOOStWrFBhYaGioqJKfC8qGwAAVFJHjhzRtm3bnD/v3LlTmZmZCgkJUYMGDTRq1Cg9+eSTaty4sSIjIzVhwgRFREQoNjZWktSsWTN1795dQ4cOVXJysvLz8zVixAgNGDCgxDtRJJINAACM89TW12+//VZdunRx/nx6vUdcXJzmz5+vRx99VHl5eRo2bJhycnJ07bXXatmyZfLz83N+ZtGiRRoxYoS6du0qHx8f9evXT0lJSaWKw2ZZluWeRyo//K8c4ekQgHLp0PrZng4BKHf8yuCf3dcnpbvlOiseinbLdcoaazYAAIBRtFEAADDM27+IjWQDAADDfLw826CNAgAAjKKyAQCAYV5e2CDZAADANHe/kKuiIdkAAMAwH+/ONVizAQAAzKKyAQCAYbRRAACAUV6ea9BGAQAAZlHZAADAMJu8u7RBsgEAgGHsRgEAADCIygYAAIaxGwUAABjl5bkGbRQAAGAWlQ0AAAzz9q+YJ9kAAMAwL881SDYAADDN2xeIsmYDAAAYRWUDAADDvLywQbIBAIBp3r5AlDYKAAAwisoGAACGeXddg2QDAADj2I0CAABgEJUNAAAM8/avmC9RsvHhhx+W+II333zzeQcDAEBl5O1tlBIlG7GxsSW6mM1mU0FBwYXEAwAAKpkSJRuFhYWm4wAAoNLy8sIGazYAADCNNsp5yMvL06pVq7R7926dOHHC5dxDDz3klsAAAKgsWCBaSt9995169uypo0ePKi8vTyEhIdq/f7+qV6+uevXqkWwAAAAXpX7PxujRo9W7d28dOnRI/v7+WrNmjXbt2qV27dpp+vTpJmIEAKBCs9lsbjkqqlInG5mZmRozZox8fHxUpUoVORwO1a9fX9OmTdNjjz1mIkYAACo0m5uOiqrUyUa1atXk43PqY/Xq1dPu3bslSUFBQfrtt9/cGx0AAKjwSp1sXHnllVq/fr0kqVOnTpo4caIWLVqkUaNGqWXLlm4PEACAis7HZnPLURoFBQWaMGGCIiMj5e/vr0svvVRPPPGELMtyzrEsSxMnTlR4eLj8/f0VExOjrVu3uvvxS59sPP300woPD5ckPfXUU6pVq5YeeOAB7du3T6+88orbAwQAoKKz2dxzlMazzz6rl156SbNnz9bmzZv17LPPatq0aZo1a5ZzzrRp05SUlKTk5GStXbtWAQEB6tatm44fP+7W5y/1bpT27ds7/7tevXpatmyZWwMCAAAX7ptvvlGfPn3Uq1cvSVKjRo30xhtvaN26dZJOVTVmzpypxx9/XH369JEkvf766woNDVVKSooGDBjgtlj41lcAAAxz124Uh8Oh3Nxcl8PhcBR7z2uuuUapqan65ZdfJEnff/+9Vq9erR49ekiSdu7cqaysLMXExDg/ExQUpKioKKWnp7v1+Utd2YiMjDzn9psdO3ZcUEAAAFQ27tq1mpiYqClTpriMTZo0SZMnTy4yd/z48crNzVXTpk1VpUoVFRQU6KmnntLAgQMlSVlZWZKk0NBQl8+FhoY6z7lLqZONUaNGufycn5+v7777TsuWLdPYsWPdFRcAADhDQkKC4uPjXcbsdnuxc99++20tWrRIixcvVosWLZSZmalRo0YpIiJCcXFxZRGuU6mTjYcffrjY8Tlz5ujbb7+94IAAAKhsSruT5GzsdvtZk4szjR07VuPHj3euvWjVqpV27dqlxMRExcXFKSwsTJKUnZ3t3Phx+uc2bdq4Jd7T3LZmo0ePHnrvvffcdTkAACoNT+xGOXr0qPO9WKdVqVLF+U3ukZGRCgsLU2pqqvN8bm6u1q5dq+jo6At+5v/ltm99fffddxUSEuKuywEAUGl44lXjvXv31lNPPaUGDRqoRYsW+u677/TCCy/onnvuccY0atQoPfnkk2rcuLEiIyM1YcIERUREKDY21q2xlDrZuPLKK11+aZZlKSsrS/v27dPcuXPdGhwAADg/s2bN0oQJE/Tggw9q7969ioiI0H333aeJEyc65zz66KPKy8vTsGHDlJOTo2uvvVbLli2Tn5+fW2OxWf/7KrESmDx5skuy4ePjo7p166pz585q2rSpW4M7X9v3HfN0CEC5dFEtf0+HAJQ7fm6r8Z/dyCWb3XKdWbc0c8t1ylqpf8XFba8BAABnV5G/sdUdSr1AtEqVKtq7d2+R8QMHDqhKlSpuCQoAAFQepa5snK3r4nA45Ovre8EBAQBQ2fh4d2Gj5MlGUlKSpFOloH//+9+qUaOG81xBQYHS0tLKzZoNAADKE5KNEpoxY4akU5WN5ORkl5aJr6+vGjVqpOTkZPdHCAAAKrQSJxs7d+6UJHXp0kXvv/++atWqZSwoAAAqE29fIFrqNRtffvmliTgAAKi0vL2NUurdKP369dOzzz5bZHzatGm67bbb3BIUAACoPEqdbKSlpalnz55Fxnv06KG0tDS3BAUAQGXiie9GKU9K3UY5cuRIsVtcq1WrptzcXLcEBQBAZeKub32tqEpd2WjVqpXeeuutIuNvvvmmmjdv7pagAACoTHzcdFRUpa5sTJgwQX379tX27dt1/fXXS5JSU1O1ePFivfvuu24PEAAAVGylTjZ69+6tlJQUPf3003r33Xfl7++v1q1ba8WKFXzFPAAAxfDyLkrpkw1J6tWrl3r16iVJys3N1RtvvKFHHnlEGRkZKigocGuAAABUdKzZOE9paWmKi4tTRESEnn/+eV1//fVas2aNO2MDAACVQKkqG1lZWZo/f75ee+015ebmqn///nI4HEpJSWFxKAAAZ+HlhY2SVzZ69+6tJk2a6IcfftDMmTO1Z88ezZo1y2RsAABUCj429xwVVYkrG59++qkeeughPfDAA2rcuLHJmAAAQCVS4srG6tWr9ddff6ldu3aKiorS7NmztX//fpOxAQBQKfjYbG45KqoSJxtXX321Xn31Vf3555+677779OabbyoiIkKFhYVavny5/vrrL5NxAgBQYXn768pLvRslICBA99xzj1avXq2NGzdqzJgxeuaZZ1SvXj3dfPPNJmIEAAAV2AW9/bRJkyaaNm2afv/9d73xxhvuigkAgEqFBaJuUKVKFcXGxio2NtYdlwMAoFKxqQJnCm7glmQDAACcXUWuSrhDRf4SOQAAUAFQ2QAAwDBvr2yQbAAAYJitIu9bdQPaKAAAwCgqGwAAGEYbBQAAGOXlXRTaKAAAwCwqGwAAGFaRv0TNHUg2AAAwzNvXbNBGAQAARlHZAADAMC/vopBsAABgmo+XfxEbbRQAAAyz2dxzlNYff/yhf/7zn6pdu7b8/f3VqlUrffvtt87zlmVp4sSJCg8Pl7+/v2JiYrR161Y3PvkpJBsAAFRChw4dUseOHVWtWjV9+umn+umnn/T888+rVq1azjnTpk1TUlKSkpOTtXbtWgUEBKhbt246fvy4W2OhjQIAgGGe2I3y7LPPqn79+po3b55zLDIy0vnflmVp5syZevzxx9WnTx9J0uuvv67Q0FClpKRowIABbouFygYAAIb52GxuOUrjww8/VPv27XXbbbepXr16uvLKK/Xqq686z+/cuVNZWVmKiYlxjgUFBSkqKkrp6elue3aJZAMAgArD4XAoNzfX5XA4HMXO3bFjh1566SU1btxYn332mR544AE99NBDWrBggSQpKytLkhQaGuryudDQUOc5dyHZAADAMHctEE1MTFRQUJDLkZiYWOw9CwsL1bZtWz399NO68sorNWzYMA0dOlTJycll/PQkGwAAGOeuNkpCQoIOHz7sciQkJBR7z/DwcDVv3txlrFmzZtq9e7ckKSwsTJKUnZ3tMic7O9t5zm3P79arAQAAY+x2uwIDA10Ou91e7NyOHTtqy5YtLmO//PKLGjZsKOnUYtGwsDClpqY6z+fm5mrt2rWKjo52a9zsRgEAwDBPvEF09OjRuuaaa/T000+rf//+WrdunV555RW98sor/z8mm0aNGqUnn3xSjRs3VmRkpCZMmKCIiAjFxsa6NRaSDQAADPNEG6FDhw5asmSJEhISNHXqVEVGRmrmzJkaOHCgc86jjz6qvLw8DRs2TDk5Obr22mu1bNky+fn5uTUWm2VZlluvWA5s33fM0yEA5dJFtfw9HQJQ7viVwT+756/f7ZbrDOrQwC3XKWtUNgAAMMzm5d/ERrIBAIBh3p1qkGwAAGBcad/+Wdmw9RUAABhFZQMAAMO8u65BsgEAgHFe3kWhjQIAAMyisgEAgGFsfQUAAEZ5exvB258fAAAYRmUDAADDaKMAAACjvDvVoI0CAAAMo7IBAIBhtFEAAIBR3t5GINkAAMAwb69seHuyBQAADKOyAQCAYd5d1yDZAADAOC/votBGAQAAZlHZAADAMB8vb6SQbAAAYBhtFAAAAIOobAAAYJiNNgoAADCJNgoAAIBBVDYAADCM3SgAAMAob2+jkGwAAGCYtycbrNkAAABGUdkAAMAwtr4CAACjfLw716CNAgAAzKKyAQCAYbRRAACAUexGAQAAMIjKBgAAhnl7G4XKBgAAhvnY3HNciGeeeUY2m02jRo1yjh0/flzDhw9X7dq1VaNGDfXr10/Z2dkXdqNikGwAAFDJrV+/Xi+//LKuuOIKl/HRo0fro48+0jvvvKNVq1Zpz5496tu3r9vvTxsFF+ytha/pm1Wp+n3Xr/K129WsVWvd88AoXdygkXPOpx+8q5XLP9W2X37WsaN5evvTNNWoGei5oAEPeXPxIi2Y95r279+ny5s01fjHJqjVGX8BoPLxZBvlyJEjGjhwoF599VU9+eSTzvHDhw/rtdde0+LFi3X99ddLkubNm6dmzZppzZo1uvrqq90WA5UNXLAfv8vQTX1v1wsvv66nZiSr4ORJ/Wv0Azp+7JhzjsNxXO2iOur2u4Z4MFLAs5Z9+ommT0vUfQ8O15vvLFGTJk31wH1DdODAAU+HBsNsNvccDodDubm5LofD4TjnvYcPH65evXopJibGZTwjI0P5+fku402bNlWDBg2Unp7u1ucn2cAFe+KFubqhZx81vOQyXdK4ieIfm6p92X9q65afnHNi+/9T/e+6R01btPJgpIBnLVwwT31v7a/YW/rp0ssu0+OTpsjPz08p77/n6dBgmM1NR2JiooKCglyOxMTEs973zTff1IYNG4qdk5WVJV9fXwUHB7uMh4aGKisr68Ie+Ay0UeB2eXlHJEk1A4M8HAlQfuSfOKHNP23SkKH3Ocd8fHx09dXX6Ifvv/NgZKhIEhISFB8f7zJmt9uLnfvbb7/p4Ycf1vLly+Xn51cW4Z1Vua5s/Pbbb7rnnnvOOed8Skowp7CwUC8nPafmrdqo0SWXeTocoNw4lHNIBQUFql27tst47dq1tX//fg9FhbLiY7O55bDb7QoMDHQ5zpZsZGRkaO/evWrbtq2qVq2qqlWratWqVUpKSlLVqlUVGhqqEydOKCcnx+Vz2dnZCgsLc+/zu/Vqbnbw4EEtWLDgnHOKKyklv/hcGUWIM819IVG7dmzT+CnPejoUACg33NVGKY2uXbtq48aNyszMdB7t27fXwIEDnf9drVo1paamOj+zZcsW7d69W9HR0Rf0vGfyaBvlww8/POf5HTt2/O01iisp/Z5beEFx4fzMfSFR675J07TZ/1GdeqGeDgcoV2oF11KVKlWKLAY9cOCA6tSp46GoUJnVrFlTLVu2dBkLCAhQ7dq1neNDhgxRfHy8QkJCFBgYqJEjRyo6OtqtO1EkDycbsbGxstlssizrrHNsf/NCebvdXqSEZHccO8tsmGBZll6a8YzS01bomVn/VljERZ4OCSh3qvn6qlnzFlq7Jl3Xdz21+r+wsFBr16ZrwB3/9HB0MK6cvkB0xowZ8vHxUb9+/eRwONStWzfNnTvX7ffxaLIRHh6uuXPnqk+fPsWez8zMVLt27co4KpTW3Oef1sovPtXExJnyrx6ggwdO9Z8DatSQ3X5qUdLBA/t16OB+7fnjN0nSrzu2yb96ddULDWchKbzGXXGDNeGxcWrRoqVatrpC/124QMeOHVPsLe5/iRLKl/LyuvKVK1e6/Ozn56c5c+Zozpw5Ru/r0WSjXbt2ysjIOGuy8XdVD5QPH6e8I0kaN/Jel/HRj03RDT1P/e/2k5R3tHjey85zjw6/p8gcoLLr3qOnDh08qLmzk7R//z41adpMc1/+t2rTRkElZ7M8+Lf5V199pby8PHXv3r3Y83l5efr222/VqVOnUl13+z7aKEBxLqrl7+kQgHLHrwz+2b1ux2G3XOeqSypmJdijyYYpJBtA8Ug2gKLKItlY76Zko0MFTTbK9dZXAABQ8fEGUQAATCsf60M9hmQDAADDystuFE8h2QAAwLC/eWVUpceaDQAAYBSVDQAADPPywgbJBgAAxnl5tkEbBQAAGEVlAwAAw9iNAgAAjGI3CgAAgEFUNgAAMMzLCxskGwAAGOfl2QZtFAAAYBSVDQAADGM3CgAAMMrbd6OQbAAAYJiX5xqs2QAAAGZR2QAAwDQvL22QbAAAYJi3LxCljQIAAIyisgEAgGHsRgEAAEZ5ea5BGwUAAJhFZQMAANO8vLRBsgEAgGHsRgEAADCIygYAAIaxGwUAABjl5bkGyQYAAMZ5ebbBmg0AAGAUlQ0AAAzz9t0oJBsAABjm7QtEaaMAAACjSDYAADDM5qajNBITE9WhQwfVrFlT9erVU2xsrLZs2eIy5/jx4xo+fLhq166tGjVqqF+/fsrOzj7v5zwbkg0AAEzzQLaxatUqDR8+XGvWrNHy5cuVn5+vG2+8UXl5ec45o0eP1kcffaR33nlHq1at0p49e9S3b98Le9Zi2CzLstx+VQ/bvu+Yp0MAyqWLavl7OgSg3PErg9WL7vp76dK65/9neN++fapXr55WrVql6667TocPH1bdunW1ePFi3XrrrZKkn3/+Wc2aNVN6erquvvpqt8QsUdkAAMA4m5v+x+FwKDc31+VwOBwliuHw4cOSpJCQEElSRkaG8vPzFRMT45zTtGlTNWjQQOnp6W59fpINAAAMs9nccyQmJiooKMjlSExM/Nv7FxYWatSoUerYsaNatmwpScrKypKvr6+Cg4Nd5oaGhiorK8utz8/WVwAAKoiEhATFx8e7jNnt9r/93PDhw/Xjjz9q9erVpkI7J5INAAAMc9drNux2e4mSi/81YsQILV26VGlpabr44oud42FhYTpx4oRycnJcqhvZ2dkKCwtzU8Sn0EYBAMA0D+xGsSxLI0aM0JIlS7RixQpFRka6nG/Xrp2qVaum1NRU59iWLVu0e/duRUdHn8dDnh2VDQAADPPE68qHDx+uxYsX64MPPlDNmjWd6zCCgoLk7++voKAgDRkyRPHx8QoJCVFgYKBGjhyp6Ohot+5Ekdj6CngVtr4CRZXF1tddB0q2Y+TvNKxd8haK7SzvSJ83b54GDRok6dRLvcaMGaM33nhDDodD3bp109y5c93eRiHZALwIyQZQVFkkG7sPuifZaBBSuvUa5QVtFAAADPPy72FjgSgAADCLygYAAIZ5+1fMk2wAAGCcd2cbtFEAAIBRVDYAADCMNgoAADDKy3MN2igAAMAsKhsAABhGGwUAABjlie9GKU9INgAAMM27cw3WbAAAALOobAAAYJiXFzZINgAAMM3bF4jSRgEAAEZR2QAAwDB2owAAALO8O9egjQIAAMyisgEAgGFeXtgg2QAAwDR2owAAABhEZQMAAMPYjQIAAIyijQIAAGAQyQYAADCKNgoAAIZ5exuFZAMAAMO8fYEobRQAAGAUlQ0AAAyjjQIAAIzy8lyDNgoAADCLygYAAKZ5eWmDZAMAAMPYjQIAAGAQlQ0AAAxjNwoAADDKy3MN2igAABhnc9NxHubMmaNGjRrJz89PUVFRWrdu3QU9yvkg2QAAoJJ66623FB8fr0mTJmnDhg1q3bq1unXrpr1795ZpHDbLsqwyvWMZ2L7vmKdDAMqli2r5ezoEoNzxK4MFBcfy3XMd/2qlmx8VFaUOHTpo9uzZkqTCwkLVr19fI0eO1Pjx490TVAlQ2QAAwDCbzT1HaZw4cUIZGRmKiYlxjvn4+CgmJkbp6elufsJzY4EoAAAVhMPhkMPhcBmz2+2y2+1F5u7fv18FBQUKDQ11GQ8NDdXPP/9sNM4zVcpk49K6lIrLA4fDocTERCUkJBT7BwHwVvzZ8D7uatVMfjJRU6ZMcRmbNGmSJk+e7J4bGFIp12ygfMjNzVVQUJAOHz6swMBAT4cDlBv82cD5Kk1l48SJE6pevbreffddxcbGOsfj4uKUk5OjDz74wHS4TqzZAACggrDb7QoMDHQ5zlYd8/X1Vbt27ZSamuocKywsVGpqqqKjo8sqZEmVtI0CAACk+Ph4xcXFqX379rrqqqs0c+ZM5eXlafDgwWUaB8kGAACV1O233659+/Zp4sSJysrKUps2bbRs2bIii0ZNI9mAMXa7XZMmTWIBHHAG/mygLI0YMUIjRozwaAwsEAUAAEaxQBQAABhFsgEAAIwi2QAAAEaRbAAAAKNINmDMnDlz1KhRI/n5+SkqKkrr1q3zdEiAR6Wlpal3796KiIiQzWZTSkqKp0MCygTJBox46623FB8fr0mTJmnDhg1q3bq1unXrpr1793o6NMBj8vLy1Lp1a82ZM8fToQBliq2vMCIqKkodOnTQ7NmzJZ16RW79+vU1cuRIjR8/3sPRAZ5ns9m0ZMkSl++sACorKhtwuxMnTigjI0MxMTHOMR8fH8XExCg9Pd2DkQEAPIFkA263f/9+FRQUFHkdbmhoqLKysjwUFQDAU0g2AACAUSQbcLs6deqoSpUqys7OdhnPzs5WWFiYh6ICAHgKyQbcztfXV+3atVNqaqpzrLCwUKmpqYqOjvZgZAAAT+BbX2FEfHy84uLi1L59e1111VWaOXOm8vLyNHjwYE+HBnjMkSNHtG3bNufPO3fuVGZmpkJCQtSgQQMPRgaYxdZXGDN79mw999xzysrKUps2bZSUlKSoqChPhwV4zMqVK9WlS5ci43FxcZo/f37ZBwSUEZINAABgFGs2AACAUSQbAADAKJINAABgFMkGAAAwimQDAAAYRbIBAACMItkAAABGkWwAldCgQYMUGxvr/Llz584aNWpUmcexcuVK2Ww25eTklPm9AZQfJBtAGRo0aJBsNptsNpt8fX112WWXaerUqTp58qTR+77//vt64oknSjSXBAGAu/HdKEAZ6969u+bNmyeHw6FPPvlEw4cPV7Vq1ZSQkOAy78SJE/L19XXLPUNCQtxyHQA4H1Q2gDJmt9sVFhamhg0b6oEHHlBMTIw+/PBDZ+vjqaeeUkREhJo0aSJJ+u2339S/f38FBwcrJCREffr00a+//uq8XkFBgeLj4xUcHKzatWvr0Ucf1ZnfQnBmG8XhcGjcuHGqX7++7Ha7LrvsMr322mv69ddfnd/dUatWLdlsNg0aNEjSqW/uTUxMVGRkpPz9/dW6dWu9++67Lvf55JNPdPnll8vf319dunRxiROA9yLZADzM399fJ06ckCSlpqZqy5YtWr58uZYuXar8/Hx169ZNNWvW1FdffaWvv/5aNWrUUPfu3Z2fef755zV//nz95z//0erVq3Xw4EEtWbLknPe8++679cYbbygpKUmbN2/Wyy+/rBo1aqh+/fp67733JElbtmzRn3/+qRdffFGSlJiYqNdff13JycnatGmTRo8erX/+859atWqVpFNJUd++fdW7d29lZmbq3nvv1fjx40392gBUJBaAMhMXF2f16dPHsizLKiwstJYvX27Z7XbrkUceseLi4qzQ0FDL4XA45y9cuNBq0qSJVVhY6BxzOByWv7+/9dlnn1mWZVnh4eHWtGnTnOfz8/Otiy++2Hkfy7KsTp06WQ8//LBlWZa1ZcsWS5K1fPnyYmP88ssvLUnWoUOHnGPHjx+3qlevbn3zzTcuc4cMGWLdcccdlmVZVkJCgtW8eXOX8+PGjStyLQDehzUbQBlbunSpatSoofz8fBUWFurOO+/U5MmTNXz4cLVq1cplncb333+vbdu2qWbNmi7XOH78uLZv367Dhw/rzz//VFRUlPNc1apV1b59+yKtlNMyMzNVpUoVderUqcQxb9u2TUePHtUNN9zgMn7ixAldeeWVkqTNmze7xCFJ0dHRJb4HgMqLZAMoY126dNFLL70kX19fRUREqGrV//tjGBAQ4DL3yJEjateunRYtWlTkOnXr1j2v+/v7+5f6M0eOHJEkffzxx7roootcztnt9vOKA4D3INkAylhAQIAuu+yyEs1t27at3nrrLdWrV0+BgYHFzgkPD9fatWt13XXXSZJOnjypjIwMtW3bttj5rVq1UmFhoVatWqWYmJgi509XVgoKCpxjzZs3l91u1+7du89aEWnWrJk+/PBDl7E1a9b8/UMCqPRYIAqUYwMHDlSdOnXUp08fffXVV9q5c6dWrlyphx56SL///rsk6eGHH9YzzzyjlJQU/fzzz3rwwQfP+Y6MRo0aKS4uTvfcc49SUlKc13z77bclSQ0bNpTNZtPSpUu1b98+HTlyRDVr1tQjjzyi0aNHa8GCBdq+fbs2bNigWbNmacGCBZKk+++/X1u3btXYsWO1ZcsWLV68WPPnzzf9KwJQAZBsAOVY9erVlZaWpgYNGqhv375q1qyZhgwZouPHjzsrHWPGjNFdd92luLg4RUdHq2bNmrrlllvOed2XXnpJt956qx588EE1bdpUQ4cOVV5eniTpoosu0pQpUzR+/HiFhoZqxIgRkqQnnnhCEyZMUGJiopo1a6bu3bvr448/VmRkpCSpQYMGeu+995SSkqLWrVsrOTlZTz/9tMHfDoCKwmadbRUZAACAG1DZAAAARpFsAAAAo0g2AACAUSQbAADAKJINAABgFMkGAAAwimQDAAAYRbIBAACMItkAAABGkWwAAACjSDYAAIBRJBsAAMCo/wf+sO6M/FH6YQAAAABJRU5ErkJggg==", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "conf_matrix = confusion_matrix(predictions.select(\"label\").collect(), predictions.select(\"prediction\").collect())\n", "sns.heatmap(conf_matrix, annot=True, fmt=\"d\", cmap=\"Blues\")\n", "plt.xlabel(\"Predicted\")\n", "plt.ylabel(\"Actual\")\n", "plt.title(\"Confusion Matrix\")\n", "plt.show()" ] }, { "cell_type": "markdown", "id": "bc98f62c", "metadata": {}, "source": [ "### Interpretation\n", "inspect feature importance scores to understand which features contribute most to predictions." ] }, { "cell_type": "code", "execution_count": 26, "id": "9ae56246", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Feature Importances:\n", "Feature 1: 0.015051080097373496\n", "Feature 2: 0.0002873794110582124\n", "Feature 3: 0.01332814031334399\n", "Feature 4: 0.0\n", "Feature 5: 0.0\n", "Feature 6: 0.0\n", "Feature 7: 0.019113264004936917\n", "Feature 8: 0.015064460075717984\n", "Feature 9: 0.014789811418442484\n", "Feature 10: 0.012263786258543456\n", "Feature 11: 0.0036664835219485485\n", "Feature 12: 0.0\n", "Feature 13: 0.010282457713879428\n", "Feature 14: 0.0\n", "Feature 15: 0.0037138960905618843\n", "Feature 16: 0.0\n", "Feature 17: 0.005921216051342099\n", "Feature 18: 0.015603721533278981\n", "Feature 19: 0.00433138753162371\n", "Feature 20: 0.0\n", "Feature 21: 0.0\n", "Feature 22: 0.017442331773253494\n", "Feature 23: 0.0\n", "Feature 24: 0.017086010558358226\n", "Feature 25: 0.00382297876028498\n", "Feature 26: 0.0\n", "Feature 27: 0.0\n", "Feature 28: 0.0\n", "Feature 29: 0.009828777231717087\n", "Feature 30: 0.0054620640660725285\n", "Feature 31: 0.0071588129266852655\n", "Feature 32: 0.019787704511670483\n", "Feature 33: 0.011630586259748912\n", "Feature 34: 0.0\n", "Feature 35: 0.0123551217832904\n", "Feature 36: 0.007273668455883249\n", "Feature 37: 0.0\n", "Feature 38: 0.02704607231853859\n", "Feature 39: 0.0\n", "Feature 40: 0.016488121681052556\n", "Feature 41: 0.01134731455210528\n", "Feature 42: 0.00441525866442517\n", "Feature 43: 0.00561919940965798\n", "Feature 44: 0.029141144522203323\n", "Feature 45: 0.0007150276262125509\n", "Feature 46: 0.015891176830203916\n", "Feature 47: 0.00883907430994379\n", "Feature 48: 0.0053535848334402055\n", "Feature 49: 0.0\n", "Feature 50: 0.0\n", "Feature 51: 0.0\n", "Feature 52: 0.018040508395540052\n", "Feature 53: 0.027209352303473152\n", "Feature 54: 0.020822936370520597\n", "Feature 55: 0.010537910297560061\n", "Feature 56: 0.017596989223655535\n", "Feature 57: 0.0\n", "Feature 58: 0.015309752835537396\n", "Feature 59: 0.0\n", "Feature 60: 0.04808339226472713\n", "Feature 61: 0.011003456535374823\n", "Feature 62: 0.008287661643170411\n", "Feature 63: 0.0\n", "Feature 64: 0.02627842644074586\n", "Feature 65: 0.018857009933697797\n", "Feature 66: 0.00021182520079705128\n", "Feature 67: 0.0304997344723786\n", "Feature 68: 0.0750252125596929\n", "Feature 69: 0.0\n", "Feature 70: 0.005647297261208397\n", "Feature 71: 0.020748097344815527\n", "Feature 72: 0.0\n", "Feature 73: 0.0\n", "Feature 74: 0.011137706974026758\n", "Feature 75: 0.01805635237077599\n", "Feature 76: 0.0\n", "Feature 77: 0.011212527737242146\n", "Feature 78: 0.0\n", "Feature 79: 0.03746679715442337\n", "Feature 80: 0.024097522808354022\n", "Feature 81: 0.01072801718424011\n", "Feature 82: 0.0\n", "Feature 83: 0.0037822651354894854\n", "Feature 84: 0.022589784097022714\n", "Feature 85: 0.006621122336113426\n", "Feature 86: 0.0030245984615245207\n", "Feature 87: 0.004278489829398828\n", "Feature 88: 0.017400495058326658\n", "Feature 89: 0.004732734467445651\n", "Feature 90: 0.001966535322976351\n", "Feature 91: 0.0\n", "Feature 92: 0.02625476239261398\n", "Feature 93: 0.00685432043116109\n", "Feature 94: 0.0\n", "Feature 95: 0.029561781984546637\n", "Feature 96: 0.0\n", "Feature 97: 0.02352814462359449\n", "Feature 98: 0.006647713461139032\n", "Feature 99: 0.0\n", "Feature 100: 0.005777649989890048\n" ] } ], "source": [ "feature_importances = model.stages[-1].featureImportances.toArray()\n", "print(\"Feature Importances:\")\n", "for i, importance in enumerate(feature_importances):\n", " print(f\"Feature {i + 1}: {importance}\")" ] }, { "cell_type": "markdown", "id": "a18a8b0e", "metadata": {}, "source": [ "### Visualize" ] }, { "cell_type": "code", "execution_count": 27, "id": "425705dc", "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjcAAAHHCAYAAABDUnkqAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8g+/7EAAAACXBIWXMAAA9hAAAPYQGoP6dpAABEyklEQVR4nO3deVxV1f7/8fcBOUwK4iUZlMQhS6+mOX7V1EwKG0wzi9Kr6PXa6HBTy1nUSrqZQzdNSzPSLKcmv2n6NW9WmmUOZOaUU5qKyk8FFQQ8rN8fPTw3ApSDB45sXs/H4zyuZ5219v6cjcn7rr323jZjjBEAAIBFeHm6AAAAAHci3AAAAEsh3AAAAEsh3AAAAEsh3AAAAEsh3AAAAEsh3AAAAEsh3AAAAEsh3AAAAEsh3AAAAEsh3AC4oqSkJNlsNuerQoUKqlatmvr06aOjR48WOMYYowULFqhdu3aqXLmyAgIC1LBhQ02cOFEXLlwodF8ff/yx7rnnHoWGhsputysyMlKPPPKI/vOf/xSp1osXL2ratGlq2bKlgoOD5efnp7p162rAgAHau3dvsb4/gLLHxrOlAFxJUlKS+vbtq4kTJ6pmzZq6ePGivvvuOyUlJSk6Olo7duyQn5+fs7/D4VCPHj20ZMkStW3bVt26dVNAQIC++eYbvf/++6pfv76++OILhYWFOccYY/T3v/9dSUlJuu2229S9e3eFh4fr+PHj+vjjj7VlyxZt2LBBrVu3LrTO1NRUderUSVu2bNH999+vmJgYVaxYUXv27NGiRYuUkpKi7OzsEj1WAK4TBgCu4J133jGSzA8//JCnffjw4UaSWbx4cZ72SZMmGUlm2LBh+ba1fPly4+XlZTp16pSnffLkyUaS+ec//2lyc3PzjZs/f775/vvvr1jnfffdZ7y8vMyyZcvyfXbx4kUzdOjQK44vqpycHJOVleWWbQEoGYQbAFdUWLj57LPPjCQzadIkZ1tGRoYJCQkxdevWNTk5OQVur2/fvkaS2bhxo3NMlSpVzC233GIuXbpUrBq/++47I8n079+/SP3bt29v2rdvn689Pj7e1KhRw/n+4MGDRpKZPHmymTZtmqlVq5bx8vIy3333nfH29jbjx4/Pt43du3cbSeb11193tp05c8YMHjzYVK9e3djtdlO7dm3z8ssvG4fD4fJ3BXB1rLkBUCyHDh2SJIWEhDjb1q9frzNnzqhHjx6qUKFCgeN69+4tSfrss8+cY06fPq0ePXrI29u7WLUsX75cktSrV69ijb+ad955R6+//roef/xxTZkyRREREWrfvr2WLFmSr+/ixYvl7e2thx9+WJKUkZGh9u3b67333lPv3r3173//W23atNHIkSM1ZMiQEqkXKO8K/tcHAP4kLS1Nqampunjxor7//ntNmDBBvr6+uv/++519du7cKUlq1KhRodu5/NmuXbvy/G/Dhg2LXZs7tnElv/32m/bt26cbbrjB2RYXF6cnnnhCO3bsUIMGDZztixcvVvv27Z1riqZOnar9+/dr27ZtuummmyRJTzzxhCIjIzV58mQNHTpUUVFRJVI3UF4xcwOgSGJiYnTDDTcoKipK3bt3V2BgoJYvX67q1as7+5w7d06SVKlSpUK3c/mz9PT0PP97pTFX445tXMlDDz2UJ9hIUrdu3VShQgUtXrzY2bZjxw7t3LlTcXFxzralS5eqbdu2CgkJUWpqqvMVExMjh8Ohr7/+ukRqBsozZm4AFMnMmTNVt25dpaWlad68efr666/l6+ubp8/lcHE55BTkzwEoKCjoqmOu5o/bqFy5crG3U5iaNWvmawsNDVXHjh21ZMkSvfDCC5J+n7WpUKGCunXr5uz3yy+/aPv27fnC0WUnT550e71AeUe4AVAkLVq0ULNmzSRJXbt21e23364ePXpoz549qlixoiSpXr16kqTt27era9euBW5n+/btkqT69etLkm655RZJ0k8//VTomKv54zbatm171f42m02mgLtgOByOAvv7+/sX2P7oo4+qb9++Sk5OVuPGjbVkyRJ17NhRoaGhzj65ubm666679Pzzzxe4jbp16161XgCu4bQUAJd5e3srMTFRx44d04wZM5ztt99+uypXrqz333+/0KAwf/58SXKu1bn99tsVEhKiDz74oNAxV9O5c2dJ0nvvvVek/iEhITp79my+9l9//dWl/Xbt2lV2u12LFy9WcnKy9u7dq0cffTRPn9q1a+v8+fOKiYkp8HXjjTe6tE8AV0e4AVAsd9xxh1q0aKHp06fr4sWLkqSAgAANGzZMe/bs0ejRo/ONWbFihZKSkhQbG6v/+Z//cY4ZPny4du3apeHDhxc4o/Lee+9p06ZNhdbSqlUrderUSXPnztUnn3yS7/Ps7GwNGzbM+b52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gQoAAFify3codqe4uDidOnVK48aNU0pKiho3bqxVq1Y5FxkfPnzYOUMjSVFRUVq9erWeffZZ3XrrrapWrZoGDx6s4cOHe+orAACA64zNGGM8XURpSk9PV3BwsNLS0hQUFOTpctwmI/uS6o9bLUnaOTFWAXaP5lYAANzKld/fbnv8AgAAwPWAcAMAACyFcAMAACylWOFm//79GjNmjB577DHnQy4///xz/fzzz24tDgAAwFUuh5uvvvpKDRs21Pfff6+PPvpI58+flyT9+OOPSkhIcHuBAAAArnA53IwYMUIvvvii1qxZk+fGeXfeeae+++47txYHAADgKpfDzU8//aQHH3wwX3vVqlWVmprqlqIAAACKy+VwU7lyZR0/fjxf+7Zt21StWjW3FAUAAFBcLoebRx99VMOHD1dKSopsNptyc3O1YcMGDRs2TL179y6JGgEAAIrM5XAzadIk3XLLLYqKitL58+dVv359tWvXTq1bt9aYMWNKokYAAIAic/ke/Xa7XXPmzNHYsWO1Y8cOnT9/XrfddptuuummkqgPAADAJS6Hm/Xr1+v222/XjTfeqBtvvLEkagIAACg2l09L3XnnnapZs6ZGjRqlnTt3lkRNAAAAxeZyuDl27JiGDh2qr776Sg0aNFDjxo01efJk/fbbbyVRHwAAgEtcDjehoaEaMGCANmzYoP379+vhhx/Wu+++q+joaN15550lUSMAAECRXdODM2vWrKkRI0bo5ZdfVsOGDfXVV1+5qy4AAIBiKXa42bBhg55++mlFRESoR48eatCggVasWOHO2gAAAFzm8tVSI0eO1KJFi3Ts2DHdddddeu2119SlSxcFBASURH0AAAAucTncfP3113ruuef0yCOPKDQ0tCRqAgAAKDaXw82GDRtKog4AAAC3KFK4Wb58ue655x75+Pho+fLlV+z7wAMPuKUwAACA4ihSuOnatatSUlJUtWpVde3atdB+NptNDofDXbUBAAC4rEjhJjc3t8A/AwAAXG9cvhR8/vz5ysrKyteenZ2t+fPnu6UoAACA4nI53PTt21dpaWn52s+dO6e+ffu6pSgAAIDicjncGGNks9nytf/2228KDg52S1EAAADFVeRLwW+77TbZbDbZbDZ17NhRFSr8d6jD4dDBgwfVqVOnEikSAACgqIocbi5fJZWcnKzY2FhVrFjR+Zndbld0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8xPNu3TpYv7+978737/55psmMjLSOBwOY4wxHTt2NJMmTcqzjQULFpiIiIgCazDGmISEBOPl5WUCAwONn5+f8+nJU6dOLXSMMcY888wz5qGHHiq01sv7vvnmm/Mcg6ysLOPv729Wr159xe0D5QFrbgCL6tChg2bNmuV8HxgYKOn3WYzExETt3r1b6enpunTpki5evKiMjAwFBATk286QIUP0j3/8QwsWLHCeWqldu7ak309Zbd++XQsXLnT2N8YoNzdXBw8eVL169QqsLS0tTRUrVlRubq4uXryo22+/XXPnzlV6erqOHTumNm3a5Onfpk0b/fjjj5J+P6V011136eabb1anTp10//336+67776mY9WzZ0/1799fb7zxhnx9fbVw4UI9+uij8vLycn7PDRs25JmpcTgcVzxuknTzzTdr+fLlunjxot577z0lJydr4MCBefrMnDlT8+bN0+HDh5WZmans7Gw1btz4ivX++OOP2rdvnypVqpSn/eLFi9q/f38xjgBgLYQbwKICAwNVp06dPG2HDh3S/fffr6eeekovvfSSqlSpovXr16tfv37Kzs4u8Jf0+PHj1aNHD61YsUKff/65EhIStGjRIj344IM6f/68nnjiCQ0aNCjfuBtvvLHQ2ipVqqStW7fKy8tLERER8vf3lySlp6df9Xs1adJEBw8e1Oeff64vvvhCjzzyiGJiYrRs2bKrji1M586dZYzRihUr1Lx5c33zzTeaNm2a8/Pz589rwoQJ6tatW76xfn5+hW7Xbrc7fwYvv/yy7rvvPk2YMEEvvPCCJGnRokUaNmyYpkyZolatWqlSpUqaPHmyvv/++yvWe/78eTVt2jRPqLzselk0DngS4QYoR7Zs2aLc3FxNmTLFOStxeX3HldStW1d169bVs88+q8cee0zvvPOOHnzwQTVp0kQ7d+7MF6KuxsvLq8AxQUFBioyM1IYNG9S+fXtn+4YNG9SiRYs8/eLi4hQXF6fu3burU6dOOn36tKpUqZJne5fXtzgcjivW4+fnp27dumnhwoXat2+fbr75ZjVp0sT5eZMmTbRnzx6Xv+efjRkzRnfeeaeeeuop5/ds3bq1nn76aWefP8+82O32fPU3adJEixcvVtWqVRUUFHRNNQFWxIJioBypU6eOcnJy9Prrr+vAgQNasGCBZs+eXWj/zMxMDRgwQOvWrdOvv/6qDRs26IcffnCebho+fLi+/fZbDRgwQMnJyfrll1/06aefuryg+I+ee+45/etf/9LixYu1Z88ejRgxQsnJyRo8eLAkaerUqfrggw+0e/du7d27V0uXLlV4eHiBNx6sWrWq/P39tWrVKp04cUJpaWmF7rdnz55asWKF5s2b51xIfNm4ceM0f/58TZgwQT///LN27dqlRYsWacyYMS59t1atWunWW2/VpEmTJEk33XSTNm/erNWrV2vv3r0aO3asfvjhhzxjoqOjtX37du3Zs0epqanKyclRz549FRoaqi5duuibb77RwYMHtW7dOg0aNEi//fabSzUBluTpRT8A3K+gRaiXTZ061URERBh/f38TGxtr5s+fbySZM2fOGGPyLvjNysoyjz76qImKijJ2u91ERkaaAQMG5FksvGnTJnPXXXeZihUrmsDAQHPrrbfmWxD8R39eUPxnDofDjB8/3lSrVs34+PiYRo0amc8//9z5+VtvvWUaN25sAgMDTVBQkOnYsaPZunWr83P9YUGxMcbMmTPHREVFGS8vL9O+fftCj4/D4TARERFGktm/f3++ulatWmVat25t/P39TVBQkGnRooV56623Cv0eCQkJplGjRvnaP/jgA+Pr62sOHz5sLl68aPr06WOCg4NN5cqVzVNPPWVGjBiRZ9zJkyedx1eS+fLLL40xxhw/ftz07t3bhIaGGl9fX1OrVi3Tv39/k5aWVmhNQHlhM8YYz8YrAAAA9+G0FAAAsBTCDQAAsBTCDQAAsBTCDQAAsBTCDQAAsBTCDQAAsBTCDQAAsBTCDQAAsBTCDQAAsBTCDQAAsBTCDQAAsBTCDQAAsJT/D8YfUnKsm5pvAAAAAElFTkSuQmCC", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "prediction_and_label = predictions.select(\"rawPrediction\", \"label\").rdd.map(lambda row: (float(row[\"rawPrediction\"][1]), float(row[\"label\"])))\n", "\n", "\n", "prediction_and_label_list = prediction_and_label.collect()\n", "\n", "# Extract probabilities and labels\n", "probabilities, labels = zip(*prediction_and_label_list)\n", "\n", "# Calculate false positive rate (fpr) and true positive rate (tpr)\n", "fpr, tpr, _ = roc_curve(labels, probabilities)\n", "\n", "# Plot ROC curve\n", "plt.plot(fpr, tpr, label='ROC Curve')\n", "plt.xlabel('False Positive Rate')\n", "plt.ylabel('True Positive Rate')\n", "plt.title('ROC Curve')\n", "plt.legend()\n", "plt.show()" ] }, { "cell_type": "code", "execution_count": 28, "id": "305c496b", "metadata": {}, "outputs": [ { "data": { "image/png": "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qA8++EDvvvuuunTpol69elXY78yZMzbrTk5OioiIkCTrN0lX9twr6+2339bFixet63PmzNGlS5cUFxdnbbv11lu1YcOGMvtdfQeoKrX169dPOTk5Np+uu3Tpkt588015eXmpe/fu1TkdoM7gDhBwk+jevbtGjRqlqVOnKisrS3369FHDhg21b98+LV26VLNmzdKDDz4oPz8/jR8/XlOnTtX999+vfv36affu3frss89sviCwPE5OTpozZ4769++vqKgoJSQkKDAwUD/88IO+++47rVmzRpLUsWNHSdLYsWMVGxsrZ2dnDRkypNwxX3nlFWVkZKhr16568skn1aBBA82bN09FRUWaPn26fS+SpI8//lheXl4qLi62fhP0pk2bFBkZqaVLl15z3xEjRuinn37SvffeqxYtWujw4cN68803FRUVZZ0bExUVJWdnZ7322mvKy8uTq6ur7r333grnZl1PcXGxevXqpYcfflh79+7VP/7xD3Xt2lW///3vber685//rD/84Q/q3bu3/vvf/2rNmjVlfp5Vqe2JJ57QvHnzNHz4cO3cuVOhoaH6+OOPtWnTJqWkpFxzrhRQLzj2Q2gArrjyseft27dfs198fLzh6elZ4fa3337b6Nixo+Hu7m54e3sbHTp0MCZMmGCcOHHC2qekpMSYMmWKERgYaLi7uxs9evQwvv322zIfm776Y/BXbNy40ejdu7fh7e1teHp6GhEREcabb75p3X7p0iXj6aefNvz8/AyLxWLzkXiV85HtXbt2GbGxsYaXl5fh4eFh9OzZ0/jqq68qdX0qqvFqVz4Gf2Vxc3MzWrRoYdx///3G/PnzjQsXLpTZ5+qPwX/88cdGnz59jObNmxsuLi5Gy5YtjVGjRhnZ2dk2+73zzjtGq1atDGdnZ5vaQkJCjPvuu6/c+ir6GPz69euNJ554wmjcuLHh5eVlPPLII8aZM2ds9i0pKTGef/55o1mzZoaHh4cRGxtr7N+/v8yY16rt6o/BG4Zh5ObmGgkJCUazZs0MFxcXo0OHDsaCBQts+lz5GPzrr79e5pzK+1kDdYXFMJihBgAAzIU5QAAAwHQIQAAAwHQIQAAAwHQIQAAAwHQIQAAAwHQIQAAAwHT4IsRylJaW6sSJE/L29rb719oDAICaYRiGzp07p6CgoDLvS7waAagcJ06cqLX3DwEAAPs6evSo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XV2N8ePHW7f7+/sbRUVF1n3++c9/Gm3atDFKS0utbUVFRYa7u7uxZs0awzAMIzAw0Jg+fbp1+8WLF40WLVpYj2UYhtG9e3dj3LhxhmEYxt69ew1JRkZGRrl1fvnll4Yk4+eff7a2XbhwwfDw8DC++uorm76PP/64MXToUMMwDCMpKclo166dzfbnn3++zFhXCwkJMf7+979bz+1vf/ubIclYuXKldfvAgQNt9vnjH/9o9O7d26btueeeszl+SEiI0bdvX5s+gwcPNuLi4iqsZenSpUbTpk2t6wsWLDAkGVu2bLG27dmzx5BkbN261TAMw5g8ebIRGRlp3f7rn7Nh2F77q8/3iq1btxrOzs7GiRMnDMMwjNzcXKNBgwbGunXrKqz173//uxESEmJdLygoMBo2bGi8//771rbi4mIjKCjI+ufjys92xYoVFY5rGIYxevRow8fH55p9DOPy9fH19b1mn/bt2xtvvvmmYRiGsWzZMsPHx8fIz88v02/nzp2GJOPQoUPXPe7Vrv4ZAPbGHSDgBq1cuVJeXl5yc3NTXFycBg8erOTkZOv2Dh06yMXFxbr+3//+V/v375e3t7e8vLzk5eWlJk2a6MKFCzpw4IDy8vKUnZ2t6Oho6z4NGjRQp06dKqwhKytLzs7O6t69e6Xr3r9/v86fP6/evXtb6/Dy8tKiRYt04MABSdKePXts6pCkLl26VGr8559/Xl5eXvLw8NBrr72madOm6b777rNuv/p89uzZo7vvvtum7e6779a+fftUUlJS4fG7dOmiPXv2WNc///xz9erVS7fccou8vb316KOP6syZMzp//ry1T4MGDXTXXXdZ19u2batGjRrZjHOjOnfurPbt22vhwoWSpH/9618KCQmx3h2pjAMHDujixYs216Vhw4bq3LlzmVqv9edDujw3yGKxVOEMLisoKND48eN1++23q1GjRvLy8tKePXusd4B69+6tkJAQtWrVSo8++qjef/9967WOjIxUr1691KFDBz300EN655139PPPP1e5BqAmVH2GHQAbPXv21Jw5c+Ti4qKgoKAyE1c9PT1t1gsKCtSxY0e9//77Zcby8/OrVg3u7u5V3ufKvJhVq1bplltusdnm6uparTp+7bnnntPw4cPl5eUlf3//Mr98r74u9nDo0CHdf//9Gj16tF599VU1adJEGzdu1OOPP67i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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "probabilities = predictions.select(\"rawPrediction\").rdd.map(lambda row: float(row[\"rawPrediction\"][1])).collect()\n", "\n", "# Plot a histogram\n", "plt.hist(probabilities, bins=50, density=True, alpha=0.5, color='b')\n", "plt.xlabel('Predicted Probability for Class 1')\n", "plt.ylabel('Density')\n", "plt.title('Prediction Distribution')\n", "plt.show()" ] }, { "cell_type": "code", "execution_count": 29, "id": "f58e4a2c", "metadata": {}, "outputs": [], "source": [ "spark.stop()" ] } ], "metadata": { "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.9.2" } }, "nbformat": 4, "nbformat_minor": 5 }