Você está na página 1de 14

Uma Breve Introdução ao PySpark

PySpark é uma linguagem de programação criada pela Apache Software Foundation que
permite a análise e processamento de grandes conjuntos de dados de forma distribuída em um
cluster de computadores.
Isso torna o PySpark uma excelente opção para lidar com dados em grande escala (Big Data) e
para realizar tarefas como:

1. Análise exploratória de dados;


2. Construção de pipelines de dados;
3. Criação de modelos de aprendizado de máquina;
4. Criação de ETLs.

A principal vantagem do PySpark é sua capacidade de lidar com grandes conjuntos de dados
de maneira eficiente e escalável. Ele usa o Apache Spark, um motor de computação
distribuído, para dividir o processamento de dados em várias máquinas. Isso permite que o
PySpark processe grandes quantidades de dados muito mais rapidamente do que seria possível
com uma única máquina.
Ecossistema

O Spark facilita o início do trabalho com sistemas de computação distribuídos.

Por meio de seu suporte de API principal para vários idiomas, bibliotecas nativas que permitem
streaming fácil, aprendizado de máquina, computação gráfica e SQL - o ecossistema Spark
oferece alguns dos recursos e recursos mais amplos de qualquer tecnologia existente.

Sistema distribuído
Um motor de computação distribuído é um software que permite que uma tarefa ou
processamento seja dividido em várias partes, para ser executado simultaneamente em
diferentes computadores de um cluster.
Isso permite que o processamento seja feito de forma mais rápida e eficiente do que seria
possível em um único computador, já que várias máquinas trabalham juntas para realizar a
tarefa em paralelo.
Site do Spark

Instalar o Spark

In [ ]:
!pip install pyspark

Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/


public/simple/
Collecting pyspark
Downloading pyspark-3.3.2.tar.gz (281.4 MB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 281.4/281.4 MB 4.6 MB/s eta 0:00:00
Preparing metadata (setup.py) ... done
Collecting py4j==0.10.9.5
Downloading py4j-0.10.9.5-py2.py3-none-any.whl (199 kB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 199.7/199.7 KB 13.2 MB/s eta 0:00:00
Building wheels for collected packages: pyspark
Building wheel for pyspark (setup.py) ... done
Created wheel for pyspark: filename=pyspark-3.3.2-py2.py3-none-any.whl size=281824
028 sha256=5e6d506fc758b6c63e474bee9c22fbe1172997f212233c9bbd9479daff02240a
Stored in directory: /root/.cache/pip/wheels/6c/e3/9b/0525ce8a69478916513509d43693
511463c6468db0de237c86
Successfully built pyspark
Installing collected packages: py4j, pyspark
Attempting uninstall: py4j
Found existing installation: py4j 0.10.9.7
Uninstalling py4j-0.10.9.7:
Successfully uninstalled py4j-0.10.9.7
Successfully installed py4j-0.10.9.5 pyspark-3.3.2

In [ ]:
# Bibliotecas Spark
from pyspark.sql import SparkSession
from pyspark.sql.functions import *
from pyspark.ml.feature import VectorAssembler
from pyspark.ml.classification import LogisticRegression
# Ignorar avisos
import warnings
warnings.filterwarnings('ignore')

# Libs para análise gráficas


import matplotlib.pyplot as plt
import seaborn as sns

# Libs de Dados
import pandas as pd
import numpy as np

O que vamos importar:

SparkSession: é a classe principal que permite a criação de uma sessão Spark para executar as
tarefas de processamento de dados e modelagem.

functions: é um módulo que contém várias funções do Spark SQL que podem ser usadas para
transformar e manipular dados.

VectorAssembler: é uma classe do PySpark que permite a conversão de várias colunas de dados
em uma única coluna de vetor, que é frequentemente usada como entrada para modelos de
aprendizado de máquina.

LogisticRegression: é uma classe de modelo de aprendizado de máquina que é


frequentemente usada para problemas de classificação binária.

Baixar a base de dados: https://drive.google.com/file/d/1Ga-


g7niXzdGoEyBoHN9dgWnZ4i3ZQ4hG/view?usp=sharing

In [ ]:
# SparkSession é usada para criar uma sessão Spark,
# que é a principal interface de programação para executar tarefas de processamento

# Create a SparkSession
spark = SparkSession.builder.appName('Projeto_Bancario').getOrCreate()

spark

Out[ ]: SparkSession - in-memory

SparkContext

Spark UI

Version v3.3.2
Master local[*]
AppName Projeto_Bancario

Breve entendimento da seção criada pelo spark:

"SparkSession - in-memory": indica que a sessão Spark foi criada na memória, ou seja, o
processamento será feito na própria máquina local.
"SparkContext": indica que o SparkContext também foi criado, o que é necessário para iniciar a
sessão Spark.

"Spark UI": é a interface do usuário do Spark, que permite visualizar informações sobre as
tarefas de processamento em execução.

"Version v3.3.2": indica a versão do Spark que está sendo usada.

"Master local[]": indica que a execução está sendo feita localmente, utilizando todos os núcleos
da máquina disponíveis ("").

"AppName Projeto_Bancario": indica o nome da aplicação, que foi definido na linha de código
que você executou.

In [ ]:
# Carregar os dados
Base_Dados = spark.read.csv('data.csv', header=True, inferSchema=True)

Estudo
Houve uma queda nas receitas de um banco português e eles gostariam de saber que medidas
tomar. Após investigação, eles descobriram que a causa raiz é que seus clientes não estão
depositando com a mesma frequência de antes.
Sabendo que os depósitos a prazo permitem que os bancos retenham um depósito por um
período de tempo específico, os bancos podem investir em produtos financeiros de maior
ganho para obter lucro.
Além disso, os bancos também têm mais chances de persuadir os clientes de depósitos a prazo
a comprar outros produtos, como fundos ou seguros, para aumentar ainda mais suas receitas.
Como resultado, o banco português gostaria de identificar os clientes existentes com maior
probabilidade de subscrever um depósito a prazo e concentrar os esforços de marketing nesses
clientes.

In [ ]:
# Instalar o polars
!pip install polars
Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/
public/simple/
Collecting polars
Downloading polars-0.16.16-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.wh
l (16.6 MB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 16.6/16.6 MB 32.7 MB/s eta 0:00:00
Requirement already satisfied: typing_extensions>=4.0.1 in /usr/local/lib/python3.9/
dist-packages (from polars) (4.5.0)
Installing collected packages: polars
Successfully installed polars-0.16.16

In [ ]:
# Quem importar mais rápido?
import polars as pl
import time

# Spark
inicio = time.time()
spark.read.csv('data.csv', header=True, inferSchema=True)
fim = time.time()
tempo_execucao = fim - inicio
print(f'Spark Executou em: {tempo_execucao:.6f} segundos')

# Polars
inicio = time.time()
pl.read_csv('data.csv')
fim = time.time()
tempo_execucao = fim - inicio
print(f'Polars Executou em: {tempo_execucao:.6f} segundos')

# Pandas
inicio = time.time()
pd.read_csv('data.csv')
fim = time.time()
tempo_execucao = fim - inicio
print(f'Pandas Executou em: {tempo_execucao:.6f} segundos')

Spark Executou em: 0.827023 segundos


Polars Executou em: 0.148070 segundos
Pandas Executou em: 0.043461 segundos

In [ ]:
# Veriricar o schema dos dados
Base_Dados.printSchema()

root
|-- age: integer (nullable = true)
|-- job: integer (nullable = true)
|-- marital: integer (nullable = true)
|-- education: integer (nullable = true)
|-- default: integer (nullable = true)
|-- housing: integer (nullable = true)
|-- loan: integer (nullable = true)
|-- contact: integer (nullable = true)
|-- month: integer (nullable = true)
|-- day_of_week: integer (nullable = true)
|-- duration: integer (nullable = true)
|-- campaign: integer (nullable = true)
|-- poutcome: integer (nullable = true)

In [ ]:
# Verificar tipo da informação
type( Base_Dados )

Out[ ]: pyspark.sql.dataframe.DataFrame
In [ ]:
# Dimensão do dataframe
def shape( df ):
num_linhas = df.count()
num_colunas = len(df.columns)
return ( num_linhas, num_colunas)

shape( Base_Dados )

Out[ ]: (8238, 13)

In [ ]:
# Verificar primeiras linhas
Base_Dados.head(5)

Out[ ]: [Row(age=32, job=4, marital=0, education=6, default=0, housing=0, loan=0, contact=0,


month=3, day_of_week=3, duration=131, campaign=5, poutcome=1),
Row(age=37, job=10, marital=3, education=6, default=0, housing=0, loan=0, contact=
0, month=4, day_of_week=3, duration=100, campaign=1, poutcome=1),
Row(age=55, job=5, marital=0, education=5, default=1, housing=2, loan=0, contact=0,
month=3, day_of_week=2, duration=131, campaign=2, poutcome=1),
Row(age=44, job=2, marital=1, education=0, default=1, housing=0, loan=0, contact=1,
month=4, day_of_week=3, duration=48, campaign=2, poutcome=1),
Row(age=28, job=0, marital=2, education=3, default=0, housing=0, loan=0, contact=0,
month=5, day_of_week=0, duration=144, campaign=2, poutcome=1)]

In [ ]:
# Mostrar os valores
Base_Dados.show( n=5, vertical=False )

+---+---+-------+---------+-------+-------+----+-------+-----+-----------+--------+-
-------+--------+
|age|job|marital|education|default|housing|loan|contact|month|day_of_week|duration|c
ampaign|poutcome|
+---+---+-------+---------+-------+-------+----+-------+-----+-----------+--------+-
-------+--------+
| 32| 4| 0| 6| 0| 0| 0| 0| 3| 3| 131|
5| 1|
| 37| 10| 3| 6| 0| 0| 0| 0| 4| 3| 100|
1| 1|
| 55| 5| 0| 5| 1| 2| 0| 0| 3| 2| 131|
2| 1|
| 44| 2| 1| 0| 1| 0| 0| 1| 4| 3| 48|
2| 1|
| 28| 0| 2| 3| 0| 0| 0| 0| 5| 0| 144|
2| 1|
+---+---+-------+---------+-------+-------+----+-------+-----+-----------+--------+-
-------+--------+
only showing top 5 rows

In [ ]:
# Tipos da informação
Base_Dados.dtypes

Out[ ]: [('age', 'int'),


('job', 'int'),
('marital', 'int'),
('education', 'int'),
('default', 'int'),
('housing', 'int'),
('loan', 'int'),
('contact', 'int'),
('month', 'int'),
('day_of_week', 'int'),
('duration', 'int'),
('campaign', 'int'),
('poutcome', 'int')]

In [ ]:
# Retornar eliminado as linhas vazias/nulas
Base_Dados = Base_Dados.na.drop()

shape( Base_Dados )

Out[ ]: (8238, 13)

In [ ]:
# Estatistica Descritiva rapida
Base_Dados.describe().show()

+-------+-----------------+------------------+------------------+------------------+
-------------------+------------------+-------------------+-------------------+-----
-------------+------------------+------------------+------------------+-------------
-----+
|summary| age| job| marital| education|
default| housing| loan| contact| mont
h| day_of_week| duration| campaign| poutcome|
+-------+-----------------+------------------+------------------+------------------+
-------------------+------------------+-------------------+-------------------+-----
-------------+------------------+------------------+------------------+-------------
-----+
| count| 8238| 8238| 8238| 8238|
8238| 8238| 8238| 8238| 8238|
8238| 8238| 8238| 8238|
| mean|39.61349842194708| 3.729424617625637|1.1704297159504735| 3.740592376790483|
0.20114105365379947|1.0728332119446469|0.32095168730274337| 0.3644088370963826| 4.22
0684632192279|2.0208788540907987|227.82058752124303| 2.207574654042243|0.93262927895
12017|
| stddev|9.021371163437701|3.5972735867352332| 0.610370961623696|2.1346174620440137|
0.4008775844260136|0.9855271779517975| 0.7179182044993212|0.48129321146348275|2.3214
638763936937|1.3867515508106179|160.44750564374866|1.3809016335523774|0.357647550026
2933|
| min| 26| 0| 0| 0|
0| 0| 0| 0| 0|
0| 36| 1| 0|
| max| 55| 11| 3| 7|
1| 2| 2| 1| 9|
4| 554| 5| 2|
+-------+-----------------+------------------+------------------+------------------+
-------------------+------------------+-------------------+-------------------+-----
-------------+------------------+------------------+------------------+-------------
-----+

In [ ]:
# Agrupamento contando
Base_Dados.groupBy('job').count().sort('job').show()

+---+-----+
|job|count|
+---+-----+
| 0| 2108|
| 1| 1813|
| 2| 296|
| 3| 205|
| 4| 579|
| 5| 354|
| 6| 322|
| 7| 773|
| 8| 164|
| 9| 1343|
| 10| 216|
| 11| 65|
+---+-----+

In [ ]:
# Executa a análise e converte o resultado para um pandas DataFrame
Analise = Base_Dados.groupBy('job').count().sort('job').toPandas()

# Cria um gráfico de barras com os resultados


plt.figure( figsize=(12, 5) )
plt.style.use('ggplot')
plt.bar( Analise['job'], Analise['count'], color='blue', alpha=0.7 )
#plt.xticks( rotation=90 )
plt.xlabel('Profissão')
plt.ylabel('Número de pessoas')
plt.title('Número de pessoas por profissão', loc='left', fontsize=14);

In [ ]:
# Análise da Classe
Base_Dados.groupBy('poutcome').count().show()

+--------+-----+
|poutcome|count|
+--------+-----+
| 1| 7147|
| 2| 268|
| 0| 823|
+--------+-----+

In [ ]:
# Separando os dados
Dados_Class = Base_Dados.select('poutcome').toPandas()['poutcome']

# Yellow brick
from yellowbrick.target import ClassBalance

visualizer = ClassBalance( labels=['Falhou', 'Não_Existe', 'Sucesso'] )


visualizer.fit( Dados_Class )
visualizer.show();
In [ ]:
# Retirar os "Não existe"
Base_Dados = Base_Dados.filter('poutcome != 1')

shape( Base_Dados )

Out[ ]: (1091, 13)

In [ ]:
# Separar os dados de caracteristcas e previsor
Selecao_Dados = VectorAssembler(
inputCols=Base_Dados.drop('poutcome').columns,
outputCol='Variaveis_Caracteristicas'
)

# Aplicando a transformação
Saida = Selecao_Dados.transform( Base_Dados )

# Selecionado a coluna previsor


Dados_Modelo = Saida.select('Variaveis_Caracteristicas', 'poutcome')
Dados_Modelo.head(5)

Out[ ]: [Row(Variaveis_Caracteristicas=DenseVector([55.0, 4.0, 1.0, 7.0, 0.0, 2.0, 0.0, 0.0,


9.0, 0.0, 156.0, 2.0]), poutcome=0),
Row(Variaveis_Caracteristicas=DenseVector([55.0, 1.0, 1.0, 2.0, 0.0, 2.0, 0.0, 0.0,
0.0, 2.0, 66.0, 1.0]), poutcome=0),
Row(Variaveis_Caracteristicas=DenseVector([43.0, 6.0, 1.0, 6.0, 0.0, 2.0, 0.0, 0.0,
5.0, 1.0, 264.0, 2.0]), poutcome=2),
Row(Variaveis_Caracteristicas=DenseVector([55.0, 5.0, 1.0, 3.0, 0.0, 0.0, 0.0, 0.0,
7.0, 1.0, 554.0, 2.0]), poutcome=0),
Row(Variaveis_Caracteristicas=DenseVector([55.0, 5.0, 1.0, 7.0, 0.0, 0.0, 2.0, 0.0,
1.0, 3.0, 554.0, 1.0]), poutcome=2)]

In [ ]:
# Separando os dados de Teste e Treino
Dados_Treino, Dados_Teste = Dados_Modelo.randomSplit( [0.75, 0.25] )

# Aplicando as features para o modelo logistico


Funcao_Logistica = LogisticRegression(featuresCol = 'Variaveis_Caracteristicas', lab

# Fitando o Modelo
Funcao_Logistica = Funcao_Logistica.fit(Dados_Treino)

# Fazendo a previsões dos dados de Teste


Previsoes = Funcao_Logistica.transform(Dados_Teste)

Variaveis_Caracteristicas: são as variáveis independentes que foram usadas para treinar o


modelo.

poutcome: é a variável dependente ou de saída que foi usada para treinar o modelo.

rawPrediction: é a saída do modelo antes que a função de ativação seja aplicada. Essa é uma
lista de valores que correspondem à pontuação de cada classe possível.

probability: é a saída do modelo após a aplicação da função de ativação. Essa é uma lista de
valores que correspondem à probabilidade de cada classe possível.
prediction: é a classe prevista para cada linha do conjunto de dados de teste. Essa é a classe
com a maior probabilidade na lista de probabilidades.

In [ ]:
Previsoes.show()

+-------------------------+--------+--------------------+--------------------+------
----+
|Variaveis_Caracteristicas|poutcome| rawPrediction| probability|predic
tion|
+-------------------------+--------+--------------------+--------------------+------
----+
| (12,[0,1,2,3,10,1...| 0|[10.9961432949925...|[0.89080618173927...|
0.0|
| (12,[0,1,2,5,10,1...| 0|[12.2096206183948...|[0.77686089866290...|
0.0|
| (12,[0,1,2,9,10,1...| 0|[9.96704333085761...|[0.91665912627638...|
0.0|
| (12,[0,1,2,9,10,1...| 0|[12.1917043638421...|[0.76749087345944...|
0.0|
| (12,[0,1,3,8,10,1...| 0|[10.4369193598411...|[0.92489743618735...|
0.0|
| (12,[0,1,5,10,11]...| 0|[11.4957041103154...|[0.85652638255111...|
0.0|
| (12,[0,2,3,8,10,1...| 0|[11.7263395251142...|[0.84722098179710...|
0.0|
| (12,[0,2,3,8,10,1...| 0|[11.0163243239734...|[0.88219861921996...|
0.0|
| (12,[0,2,3,8,10,1...| 0|[10.6537119208970...|[0.89894424950635...|
0.0|
| (12,[0,2,3,8,10,1...| 0|[11.6887845048612...|[0.84339161028003...|
0.0|
| (12,[0,2,3,8,10,1...| 0|[11.7929634649337...|[0.82761976458876...|
0.0|
| (12,[0,2,3,9,10,1...| 0|[13.9875007256378...|[0.60128956774058...|
0.0|
| (12,[0,2,3,9,10,1...| 0|[12.5343114528007...|[0.77224704395882...|
0.0|
| (12,[0,2,3,9,10,1...| 0|[11.8394497424915...|[0.75508060916572...|
0.0|
| (12,[0,2,3,9,10,1...| 2|[14.1834463204288...|[0.50592644367051...|
0.0|
| (12,[0,3,8,9,10,1...| 0|[11.2000964118972...|[0.88213394523071...|
0.0|
| (12,[0,3,8,9,10,1...| 2|[12.2438776016630...|[0.76971167369166...|
0.0|
| (12,[0,3,8,9,10,1...| 2|[14.1733430715746...|[0.55556754194465...|
0.0|
| (12,[0,3,8,9,10,1...| 0|[11.8307721047813...|[0.81030928239809...|
0.0|
| [26.0,0.0,1.0,3.0...| 0|[13.5067004612909...|[0.62208025721220...|
0.0|
+-------------------------+--------+--------------------+--------------------+------
----+
only showing top 20 rows
In [ ]:
# Calculando a acurácia
from pyspark.ml.evaluation import MulticlassClassificationEvaluator

avaliador = MulticlassClassificationEvaluator(
predictionCol='prediction',
labelCol='poutcome',
metricName='accuracy'
)

acuracia = avaliador.evaluate(Previsoes)

print('A acurácia do modelo é: {:.2f}%'.format(acuracia * 100) )

A acurácia do modelo é: 70.75%

In [ ]:
# Matriz de confusão
from sklearn.metrics import confusion_matrix

# Separar os dados de Y_TRUE, Y_PRED


df_previsoes = Previsoes.select('prediction', 'poutcome').toPandas()

# Gero a matriz
matriz_confusao = confusion_matrix(df_previsoes['poutcome'], df_previsoes['predictio

print(matriz_confusao)

[[206 7]
[ 79 2]]

In [ ]:

Você também pode gostar