
Compartilhar:
Aboze Brain John é analista de negócios de tecnologia na Axa Mansard. Ele possui experiência em ciência de dados e análise de dados, pesquisa de produtos e redação técnica. Brain tem atuado em projetos completos de análise de dados, abrangendo desde a coleta, exploração, transformação/preparação e modelagem de dados até a obtenção de insights de negócios úteis, além de exercer liderança em conhecimento.
Detecção de spam por SMS com aprendizado de máquina em Python
Este artigo foi atualizado em abril de 2025
Neste tutorial, você vai criar um aplicativo web para detecção de spam por SMS. Esse aplicativo será desenvolvido em Python, utilizando o framework Flask, e incluirá um modelo de aprendizado de máquina que você treinará para detectar spam por SMS. Trabalharemos com a SMS API da Vonage para que você possa classificar as mensagens SMS enviadas ao número de telefone que você registrou na sua conta da Vonage.
Pré-requisitos
Para comprar um número de telefone virtual, acesse seu painel da API e siga as etapas mostradas abaixo.
Purchase a phone number
Acesse seu painel da API
Acesse CRIAR E GERENCIAR > Numbers > Comprar números.
Selecione os atributos necessários e, em seguida, clique em “Pesquisar”
Clique no botão “Comprar” ao lado do número desejado e confirme sua compra
Para confirmar que você adquiriu o número virtual, acesse o menu de navegação à esquerda, na seção “CRIAR E GERENCIAR”, clique em “Numbers” e, em seguida, em “Seus números”
Python instalado. O A distribuição inclui várias bibliotecas úteis para ciência de dados.
Conhecimentos básicos sobre Flask, HTML e CSS.
Estrutura de arquivos
A seguir, é apresentada uma visão geral da estrutura de diretórios deste projeto:
├── README.md
├── dataset
│ └── spam.csv
├── env
│ ├── bin
│ ├── etc
│ ├── include
│ ├── lib
│ ├── pyvenv.cfg
│ └── share
├── model
│ ├── spam_model.pkl
│ └── tfidf_model.pkl
├── notebook
│ └── project_notebook.ipynb
├── requirements.txt
├── script
└── web_app
├── app.py
├── static
└── templatesCriaremos todos os arquivos na árvore de diretórios acima ao longo das etapas deste tutorial.
Configurar um ambiente virtual do Python
Precisamos criar um ambiente isolado para as diversas dependências do Python específicas deste projeto.
Primeiro, crie uma nova pasta de desenvolvimento. No terminal, execute:
Em seguida, crie um novo ambiente virtual de Python. Se você estiver usando Anaconda, você pode executar o seguinte comando:
Em seguida, você pode ativar o ambiente usando:
Se você estiver usando uma distribuição padrão do Python, crie um novo ambiente virtual executando o comando abaixo:
Para ativar o novo ambiente em um computador Mac ou Linux, execute:
Se você estiver usando um computador com Windows, configure o ambiente da seguinte maneira:
Independentemente do método que você utilizou para criar e ativar o ambiente virtual, seu prompt deve ter sido modificado para ficar assim:
Instalar os pacotes necessários
Em seguida, você instalará todos os pacotes necessários para este tutorial. No seu novo ambiente, instale os seguintes pacotes (que incluem bibliotecas e dependências):
Observação: Para criar um projeto de ciência de dados reproduzível, utilize as versões que incluí aqui. Essas eram as versões mais atualizadas no momento da redação deste artigo.
Aqui estão alguns detalhes sobre esses pacotes:
jupyterlab serve para a construção de modelos e a exploração de dados.
flask serve para criar o servidor de aplicativos e as páginas.
lightgbm é o algoritmo de aprendizado de máquina utilizado para construir nosso modelo
nexmo é uma biblioteca em Python para interagir com seu Account da Vonage
matplotlib, plotly, plotly-express servem para visualização de dados
python-dotenv é um pacote para gerenciar variáveis de ambiente, como chaves de API e outros valores de configuração.
nltk significa operações de linguagem natural
numpy serve para cálculos com matrizes
pandas serve para manipular e organizar dados estruturados.
regex serve para operações com expressões regulares
scikit-learn é um kit de ferramentas de aprendizado de máquina
nuvem de palavras é usado para criar imagens de nuvem de palavras a partir de textos
Após a instalação, inicie o Jupyter Lab executando o seguinte comando:
Isso abre a popular interface do Jupyter Lab no seu navegador, onde você realizará algumas atividades interativas de exploração de dados e construção de modelos.
A interface do JupyterLab é mostrada aqui JupyterLab.
Construir e treinar o modelo de detecção de SMS
Agora que seu ambiente está pronto, você vai baixar os dados de treinamento de SMS e construir um modelo simples de aprendizado de máquina para classificar as mensagens de SMS. O conjunto de dados de spam para este projeto pode ser baixado aqui. Os conjuntos de dados contêm 5.574 mensagens com os respectivos rótulos de spam e ham (legítimo). Mais informações sobre o conjunto de dados podem ser encontradas aqui. Com esses dados, vamos treinar um modelo de aprendizado de máquina capaz de classificar corretamente as mensagens SMS como ham ou spam. Esses procedimentos serão realizados em um notebook do Jupyter, que, em nosso diretório de arquivos, é chamado de 'project_notebook'
Análise Exploratória de Dados (EDA)
Aqui, vamos aplicar diversas técnicas para analisar os dados e compreendê-los melhor.
Importar bibliotecas e dados
As bibliotecas necessárias para este projeto podem ser importadas para project_notebook.ipynb da seguinte maneira:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import plotly_express as px
import wordcloud
import nltk
import warnings
warnings.filterwarnings('ignore')O conjunto de dados de spam localizado no diretório de conjuntos de dados chamado spam.csv pode ser importado da seguinte maneira:
df = pd.read_csv("../dataset/spam.csv", encoding='latin-1')Observação: A codificação de caracteres deste conjunto de dados é latin-1 (ISO/IEC 8859-1).
A seguir, temos uma visão geral do conjunto de dados:
df.head()
Dataset overview
O conjunto de dados contém 5 colunas. A coluna v1 é o rótulo do conjunto de dados (“ham” ou “spam”) e a coluna v2 contém o texto da mensagem SMS. As colunas “Unnamed: 2”, “Unnamed: 3” e “Unnamed: 4” contêm “NaN” (não é um número), o que indica valores ausentes. Elas não são necessárias, portanto podem ser removidas, já que não serão úteis na construção do modelo. O trecho de código a seguir irá excluir e renomear as colunas para melhorar a compreensibilidade do conjunto de dados:
df.drop(columns=['Unnamed: 2', 'Unnamed: 3', 'Unnamed: 4'], inplace=True)
df.rename(columns = {'v1':'class_label','v2':'message'},inplace=True)
df.head()
Rename columns
Vamos dar uma olhada na distribuição dos rótulos:
fig = px.histogram(df, x="class_label", color="class_label", color_discrete_sequence=["#871fff","#ffa78c"])
fig.show()
Distributions of labels
Temos um conjunto de dados desequilibrado, com 747 mensagens de spam e 4.825 mensagens legítimas.
fig = px.pie(df.class_label.value_counts(),labels='index', values='class_label', color="class_label", color_discrete_sequence=["#871fff","#ffa78c"] )
fig.show()
Labels pie chart
O spam representa 13,4% do conjunto de dados, enquanto o ham representa 86,6% do conjunto de dados.
A seguir, vamos nos aprofundar um pouco na engenharia de características. O comprimento das mensagens pode nos dar algumas pistas. Vamos dar uma olhada:
df['length'] = df['message'].apply(len)
df.head()
Message length
fig = px.histogram(df, x="length", color="class_label", color_discrete_sequence=["#871fff","#ffa78c"] )
fig.show()
length distribution - ham
Length distribution - spam
Pode-se observar que as mensagens legítimas são mais curtas do que as mensagens de spam, já que a distribuição dos comprimentos dessas mensagens se concentra em torno de 30-40 e 155-160 caracteres, respectivamente.
Ter uma visão geral das palavras mais comuns usadas em spams e e-mails legítimos nos ajudará a compreender melhor o conjunto de dados. Uma nuvem de palavras pode dar uma ideia de que tipo de palavras predominam em cada classe.
Para criar uma nuvem de palavras, primeiro separe as classes em dois dataframes do pandas e adicione uma função simples para gerar a nuvem de palavras, conforme mostrado a seguir:
data_ham = df[df['class_label'] == "ham"].copy()
data_spam = df[df['class_label'] == "spam"].copy()
def show_wordcloud(df, title):
text = ' '.join(df['message'].astype(str).tolist())
stopwords = set(wordcloud.STOPWORDS)
fig_wordcloud = wordcloud.WordCloud(stopwords=stopwords, background_color="#ffa78c",
width = 3000, height = 2000).generate(text)
plt.figure(figsize=(15,15), frameon=True)
plt.imshow(fig_wordcloud)
plt.axis('off')
plt.title(title, fontsize=20)
plt.show()Abaixo está o código que exibe uma nuvem de palavras para SMS de spam:
show_wordcloud(data_spam, "Spam messages")
word cloud spam
Você também pode exibir a nuvem de palavras para mensagens SMS amadoras:
show_wordcloud(data_ham, "ham messages")
word cloud ham
Pré-processar os dados
O processo de converter dados em algo que um computador possa compreender é conhecido como pré-processamento. No contexto deste artigo, isso envolve processos e técnicas para preparar nossos dados de texto para o nosso algoritmo de aprendizado de máquina
Primeiro, vamos converter o rótulo para o formato numérico. Isso é essencial antes do treinamento do modelo, pois os modelos de aprendizado profundo precisam de dados no formato numérico.
df['class_label'] = df['class_label'].map( {'spam': 1, 'ham': 0})Em seguida, processaremos o conteúdo da mensagem com Expressões Regulares (Regex) para manter a uniformidade dos endereços de e-mail e de sites, números de telefone e outros números, codificar símbolos, remover sinais de pontuação e espaços em branco e, por fim, converter todo o texto para letras minúsculas:
# Replace email address with 'emailaddress'
df['message'] = df['message'].str.replace(r'^.+@[^\.].*\.[a-z]{2,}$', 'emailaddress')
# Replace urls with 'webaddress'
df['message'] = df['message'].str.replace(r'^http\://[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(/\S*)?$', 'webaddress')
# Replace money symbol with 'money-symbol'
df['message'] = df['message'].str.replace(r'£|\$', 'money-symbol')
# Replace 10 digit phone number with 'phone-number'
df['message'] = df['message'].str.replace(r'^\(?[\d]{3}\)?[\s-]?[\d]{3}[\s-]?[\d]{4}$', 'phone-number')
# Replace normal number with 'number'
df['message'] = df['message'].str.replace(r'\d+(\.\d+)?', 'number')
# remove punctuation
df['message'] = df['message'].str.replace(r'[^\w\d\s]', ' ')
# remove whitespace between terms with single space
df['message'] = df['message'].str.replace(r'\s+', ' ')
# remove leading and trailing whitespace
df['message'] = df['message'].str.replace(r'^\s+|\s*?$', ' ')
# change words to lower case
df['message'] = df['message'].str.lower()Daqui para frente, removeremos as palavras irrelevantes do conteúdo da mensagem. Palavras irrelevantes são palavras que os mecanismos de busca foram programados para ignorar, tanto ao indexar entradas para pesquisa quanto ao recuperá-las como resultado de uma consulta de busca, como “o”, “um”, “uma”, “em”, “mas”, “porque” etc.
from nltk.corpus import stopwords
stop_words = set(stopwords.words('english'))
df['message'] = df['message'].apply(lambda x: ' '.join(term for term in x.split() if term not in stop_words))A seguir, extrairemos a forma-base das palavras, removendo os afixos delas. Esse processo é chamado de stemming, pois pode ser comparado ao corte dos galhos de uma árvore até ficarem apenas os troncos. Existem inúmeros algoritmos de stemming, tais como:
Algoritmo de Stemmer de Porter
Lovins Stemmer
Dawson Stemmer
Krovetz Stemmer
Xerox Stemmer
Redutor de radicais N-Gram
Descaroçador Snowball
Lancaster Stemmer
Alguns desses algoritmos de stemming são agressivos e dinâmicos. Outros se aplicam a idiomas além do inglês, e o tamanho dos dados de texto afeta diversos aspectos da eficiência. Para este artigo, utilizou-se o Snowball Stemmer devido à sua velocidade computacional.
Observação: Ao utilizar esses algoritmos de stemming, tome cuidado para não aplicar o stemming em excesso nem de forma insuficiente.
ss = nltk.SnowballStemmer("english")
df['message'] = df['message'].apply(lambda x: ' '.join(ss.stem(term) for term in x.split()))Os algoritmos de aprendizado de máquina não podem trabalhar diretamente com texto bruto. O texto precisa ser convertido em números — mais especificamente, em vetores de números. Vamos dividir as mensagens (dados de texto em frases) em palavras. Esse é um requisito em tarefas de processamento de linguagem natural, nas quais cada palavra precisa ser capturada e submetida a análises adicionais. Primeiro, criamos um modelo Bag of Words (BOW) para extrair características do texto:
sms_df = df['message']
from nltk.tokenize import word_tokenize
# creating a bag-of-words model
all_words = []
for sms in sms_df:
words = word_tokenize(sms)
for w in words:
all_words.append(w)
all_words = nltk.FreqDist(all_words)Vamos dar uma olhada no número total de palavras:
print('Number of words: {}'.format(len(all_words)))
Number of words 6526
Agora, represente graficamente as 10 palavras mais comuns nos dados do texto:
all_words.plot(10, title='Top 10 Most Common Words in Corpus');
Most common words
A seguir, implementaremos uma técnica de PLN — frequência de termos e frequência inversa de documentos — para avaliar a importância das palavras nos dados do texto. Em resumo, essa técnica simplesmente define o que é uma “palavra relevante”. O modelo `tfidf_model`, criado a partir dessa técnica de PLN, será salvo (serializado) no disco local para, posteriormente, transformar os dados de teste do nosso aplicativo web:
from sklearn.feature_extraction.text import TfidfVectorizer
tfidf_model = TfidfVectorizer()
tfidf_vec=tfidf_model.fit_transform(sms_df)
import pickle
#serializing our model to a file called model.pkl
pickle.dump(tfidf_model, open("../model/tfidf_model.pkl","wb"))
tfidf_data=pd.DataFrame(tfidf_vec.toarray())
tfidf_data.head()
tfidf
O dataframe resultante tem 5.572 colunas por 6.506 linhas. Para treinar e validar o desempenho do nosso modelo de aprendizado de máquina, precisamos dividir os dados em conjuntos de treinamento e de teste, respectivamente. O conjunto de treinamento deve ser posteriormente dividido em um conjunto de treinamento e um conjunto de validação.
### Separating Columns
df_train = tfidf_data.iloc[:4457]
df_test = tfidf_data.iloc[4457:]
target = df['class_label']
df_train['class_label'] = target
Y = df_train['class_label']
X = df_train.drop('class_label',axis=1)
# splitting training data into train and validation using sklearn
from sklearn import model_selection
X_train,X_test,y_train,y_test = model_selection.train_test_split(X,Y,test_size=.2, random_state=42)A proporção de divisão para o conjunto de validação é de 20% dos dados de treinamento.
Construção de modelos
Utilizaremos um algoritmo de aprendizado de máquina conhecido como LightGBM. Trata-se de uma estrutura de gradient boosting que utiliza algoritmos de aprendizado baseados em árvores. Ele apresenta as seguintes vantagens:
Maior velocidade de treinamento e maior eficiência
Menor uso de memória
Maior precisão
Suporte ao aprendizado paralelo e com GPU
Capaz de lidar com grandes volumes de dados
A métrica de desempenho para este projeto é o índice F1. Essa métrica leva em consideração tanto a precisão quanto o recall para calcular o índice. O índice F1 atinge seu melhor valor em 1 e seu pior valor em 0.
import lightgbm as lgb
from sklearn.metrics import f1_score
def train_and_test(model, model_name):
model.fit(X_train, y_train)
pred = model.predict(X_test)
print(f'F1 score is: {f1_score(pred, y_test)}')
for depth in [1,2,3,4,5,6,7,8,9,10]:
lgbmodel = lgb.LGBMClassifier(max_depth=depth, n_estimators=200, num_leaves=40)
print(f"Max Depth {depth}")
print(" ")
print(" ")
train_and_test(lgbmodel, "Light GBM")
F1 score
A partir dessa iteração, percebe-se que a Profundidade Máxima de seis (6) apresenta a maior pontuação F1, de 0,9285714285714285. Em seguida, realizaremos uma busca em grade aleatória para identificar os melhores parâmetros para o modelo:
from sklearn.model_selection import RandomizedSearchCV
lgbmodel_bst = lgb.LGBMClassifier(max_depth=6, n_estimators=200, num_leaves=40)
param_grid = {
'num_leaves': list(range(8, 92, 4)),
'min_data_in_leaf': [10, 20, 40, 60, 100],
'max_depth': [3, 4, 5, 6, 8, 12, 16, -1],
'learning_rate': [0.1, 0.05, 0.01, 0.005],
'bagging_freq': [3, 4, 5, 6, 7],
'bagging_fraction': np.linspace(0.6, 0.95, 10),
'reg_alpha': np.linspace(0.1, 0.95, 10),
'reg_lambda': np.linspace(0.1, 0.95, 10),
"min_split_gain": [0.0, 0.1, 0.01],
"min_child_weight": [0.001, 0.01, 0.1, 0.001],
"min_child_samples": [20, 30, 25],
"subsample": [1.0, 0.5, 0.8],
}
model = RandomizedSearchCV(lgbmodel_bst, param_grid, random_state=1)
search = model.fit(X_train, y_train)
search.best_params_
best parameters search
Usaremos os melhores parâmetros para treinar o modelo:
best_model = lgb.LGBMClassifier(subsample=0.5,
reg_lambda= 0.47777777777777775,
reg_alpha= 0.5722222222222222,
num_leaves= 88,
min_split_gain= 0.01,
min_data_in_leaf= 10,
min_child_weight= 0.01,
min_child_samples= 30,
max_depth= 3,
learning_rate= 0.1,
bagging_freq= 3,
bagging_fraction= 0.6,
random_state=1)
best_model.fit(X_train,y_train)
Trained model
Vamos verificar o desempenho do modelo com base em sua previsão:
prediction = best_model.predict(X_test)
print(f'F1 score is: {f1_score(prediction, y_test)}')
Model prediction
Como última etapa, faremos um treinamento completo com o conjunto de dados para que nosso aplicativo web possa fazer previsões para dados que ainda não viu. Vamos salvar o modelo em nosso computador local:
best_model.fit(tfidf_data, target)
pickle.dump(best_model, open("../model/spam_model.pkl","wb")) Incorporar o modelo em um aplicativo Flask
Agora que você já tem o modelo treinado, vamos criar um aplicativo Flask que lerá as mensagens enviadas e recebidas por meio da SMS API da Vonage e as classificará como spam ou ham. O resultado final será exibido em um painel de SMS que você também definirá nesta seção.
O web_app diretório é composto por:
├── app.py
├── static
│ ├── Author.png
│ ├── style.css
│ ├── style2.css
│ └── vonage_logo.svg
└── templates
├── inbox.html
├── index.html
└── predict.htmlNo seu editor de código, abra um novo arquivo chamado .env (observe o ponto inicial) e adicione as seguintes credenciais:
API_KEY=<Your API key>
API_SECRET=<Your API secret>
Isso é importante por motivos de segurança, já que você nunca deve inserir seus segredos diretamente no código da sua aplicação.
Em seguida, criamos um arquivo chamado app.py no web_app diretório. Importaremos bibliotecas para construir com sucesso o aplicativo web. Em seguida, carregaremos nossas credenciais da API da Vonage a partir do .env arquivo e iniciaremos o aplicativo Flask. Também importaremos os modelos salvos do nosso notebook.
import os
import warnings
import nexmo
from flask import Flask, render_template, url_for, request, session
import pickle
import pandas as pd
import nltk
from nltk.corpus import stopwords
from sklearn.feature_extraction.text import TfidfVectorizer
from dotenv import load_dotenv
load_dotenv()
API_KEY = os.getenv("API_KEY")
API_SECRET = os.getenv("API_SECRET")
client = nexmo.Client(key=API_KEY, secret=API_SECRET)
warnings.filterwarnings("ignore")
app = Flask(__name__)
# secret key is needed for session
app.secret_key = os.getenv('SECRET_KEY')Após a instância da aplicação Flask, utilizamos as sessões do Flask para auxiliar na retenção de dados em diversos intervalos de registro do servidor. Essas sessões exigem que você tenha uma chave secreta — você pode salvar o valor da chave secreta no .env arquivo e carregá-la da mesma forma que fizemos com as credenciais da API.
A seguir, definimos três funções relacionadas às rotas: home(), inbox(), e predict(). Os respectivos modelos para essas rotas são index.html, inbox.html, e predict.html, formatados com duas folhas de estilo, stlye.css e stlye2.css.
A rota “home/index” fornece a interface para enviar a mensagem:
@app.route('/', methods=['GET', 'POST'])
def home():
return render_template('index.html')A interface é mostrada a seguir:
Home interface
O arquivo de apoio index.html no templates diretório deve ter a seguinte aparência:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Spam detection Project</title>
<link rel="stylesheet" href="../static/style.css">
</head>
<body>
<nav>
<img src="{{url_for('static', filename='vonage_logo.svg')}}">
</nav>
<section>
<div class="side">
<img src="{{url_for('static', filename='Author.png')}}" width="350px" height="350px">
<h4>Author: Aboze Brain John Jnr</h4>
<h2>Project: SMS spam detection system</h2>
<h2>using Machine Learning, Python, Flask and</h2>
<h2>Vonage API</h2>
</div>
<div class="vl"></div>
<div class="main">
<h1>Machine Learning App with Flask</h1>
<p>Send an SMS</p>
<form action="/inbox" method="POST">
<input id="to_number" class="form-control" name="to_number" type="tel" placeholder="Phone Number"/>
<br>
<br>
<textarea id="message" class="form-control" name="message" placeholder="Your text message goes here" rows="10" cols="50"></textarea>
<br>
<br>
<input type="submit" class="btn-info" value="Send SMS">
</form>
</div>
</section>
</body>
</html>
A próxima rota é a rota da caixa de entrada, onde são armazenadas as mensagens enviadas e o número de telefone do remetente, provenientes do índice. A SMS API da Vonage é utilizada aqui para inicializar o objeto cliente e enviar a mensagem:
@app.route('/inbox', methods=['GET', 'POST'])
def inbox():
""" A POST endpoint that sends an SMS. """
# Extract the form values:
to_number = request.form['to_number']
message = request.form['message']
session['to_number'] = to_number
session['message'] = message
# Send the SMS message:
result = client.send_message({
'from': 'Vonage APIs',
'to': to_number,
'text': message,
})
return render_template('inbox.html', number=to_number, msg=message)A interface é mostrada a seguir:
Inbox interface
O arquivo de apoio inbox.html no templates diretório tem a seguinte aparência:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Prediction</title>
<link rel="stylesheet" href="../static/style2.css">
</head>
<body>
<nav>
<img src="{{url_for('static', filename='vonage_logo.svg')}}">
</nav>
</nav>
<section>
<div class="side">
<img src="{{url_for('static', filename='Author.png')}}" width="350px" height="350px">
<h4>Author: Aboze Brain John Jnr</h4>
<h2>Project: SMS spam detection system</h2>
<h2>using Machine Learning, Python, Flask and</h2>
<h2>Vonage API</h2>
</div>
<div class="vl"></div>
<div class="main">
<h1>Inbox</h1>
<br>
<table class="table" >
<tr>
<th scope="col">From</th>
<th scope="col">Body</th>
</tr>
<tr scope='row'>
<td>{{number}}</td>
<td>{{msg}}</td>
</tr>
</table>
<br>
<br>
<form action="/predict" method="POST">
<input type="submit" class="btn-info" value="Predict">
</form>
<!-- <input type="submit" class="btn-info" value="Predict" formaction="/predict" method="POST"> -->
</div>
</section>
</body>
</html>
A última etapa é dedicada à nossa previsão. Ela aplica todas as técnicas de pré-processamento utilizadas anteriormente para treinar o modelo de aprendizado de máquina aos novos dados, na forma de mensagens da caixa de entrada:
@app.route('/predict', methods=['POST'])
def predict():
model = pickle.load(open("../model/spam_model.pkl", "rb"))
tfidf_model = pickle.load(open("../model/tfidf_model.pkl", "rb"))
if request.method == "POST":
message = session.get('message')
message = [message]
dataset = {'message': message}
data = pd.DataFrame(dataset)
data["message"] = data["message"].str.replace(
r'^.+@[^\.].*\.[a-z]{2,}$', 'emailaddress')
data["message"] = data["message"].str.replace(
r'^http\://[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(/\S*)?$', 'webaddress')
data["message"] = data["message"].str.replace(r'£|\$', 'money-symbol')
data["message"] = data["message"].str.replace(
r'^\(?[\d]{3}\)?[\s-]?[\d]{3}[\s-]?[\d]{4}$', 'phone-number')
data["message"] = data["message"].str.replace(r'\d+(\.\d+)?', 'number')
data["message"] = data["message"].str.replace(r'[^\w\d\s]', ' ')
data["message"] = data["message"].str.replace(r'\s+', ' ')
data["message"] = data["message"].str.replace(r'^\s+|\s*?$', ' ')
data["message"] = data["message"].str.lower()
stop_words = set(stopwords.words('english'))
data["message"] = data["message"].apply(lambda x: ' '.join(
term for term in x.split() if term not in stop_words))
ss = nltk.SnowballStemmer("english")
data["message"] = data["message"].apply(lambda x: ' '.join(ss.stem(term)
for term in x.split()))
# tfidf_model = TfidfVectorizer()
tfidf_vec = tfidf_model.transform(data["message"])
tfidf_data = pd.DataFrame(tfidf_vec.toarray())
my_prediction = model.predict(tfidf_data)
return render_template('predict.html', prediction=my_prediction)A interface é mostrada a seguir:
Prediction interface
O arquivo de apoio predict.html no templates diretório tem a seguinte aparência:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Prediction</title>
<link rel="stylesheet" href="../static/style2.css">
</head>
<body>
<nav>
<img src="{{url_for('static', filename='vonage_logo.svg')}}">
</nav>
<section>
<div class="side">
<img src="{{url_for('static', filename='Author.png')}}" width="350px" height="350px">
<h4>Author: Aboze Brain John Jnr</h4>
<h2>Project: SMS spam detection system</h2>
<h2>using Machine Learning, Python, Flask and</h2>
<h2>Vonage API</h2>
</div>
<div class="vl"></div>
<div class="main results">
<h1>Machine Learning Prediction</h1>
{% if prediction == 1%}
<h2 style="color:red; font-size: x-large;">This looks like a Spam</h2>
<span style='font-size:100px;'>😡</span>
{% elif prediction == 0%}
<h2 style="color:green; font-size: x-large;">This looks like a Ham</h2>
<span style='font-size:100px;'>😀</span>
{% endif %}
</div>
</section>
</body>
</html>
No final do arquivo Python, adicione este código para iniciar um servidor local:
if __name__ == '__main__':
app.run(debug=True)O CSS minimizado das duas folhas de estilo complementares utilizadas neste projeto é apresentado a seguir.
Para style.css:
*{box-sizing:border-box;padding:0;margin:0}body{color:#131415;font-family:spezia,sans-serif}nav{position:sticky;padding-top:10px}section{display:flex;flex-wrap:nowrap;padding:50px 10px}section h4{font-size:12px;font-weight:400;padding-top:5px}section h2{font-size:17px;font-weight:700;padding-top:15px}.vl{border-left:2px solid #310069;margin-left:50px;height:100vh}.main{margin-left:100px}.main h1{font-size:40px;padding-bottom:15px}.main p{font-size:24px;padding-bottom:15px}.btn-info{color:#310069;height:50px;width:100px;border-radius:8px}Para style2.css:
*{box-sizing:border-box;padding:0;margin:0}body{color:#131415;font-family:spezia,sans-serif}nav{position:sticky;padding-top:10px}section{display:flex;flex-wrap:nowrap;padding:50px 10px}section h4{font-size:12px;font-weight:400;padding-top:5px}section h2{font-size:17px;font-weight:700;padding-top:15px}.vl{border-left:2px solid #310069;margin-left:50px;height:100vh}.main{margin-left:100px}td,th{border:3px solid #ddd;text-align:left;padding:20px}tr:nth-child(even){background-color:#ddd}input{width:80px;height:40px;border-radius:8px;color:#310069}button{width:80px;height:40px;border-radius:8px;color:#310069}Agora você pode testar seu aplicativo! Para iniciar o servidor, abra a pasta raiz em um terminal e, em seguida, execute o seguinte no web_app diretório:
Se você seguiu todas as etapas acima, deverá ver seu servidor em funcionamento, conforme mostrado a seguir:
Server output
Digite http://localhost:5000/ na barra de endereços para se conectar ao aplicativo.
Conclusão
Com isso, chegamos ao fim deste tutorial. Você pode experimentar outros exemplos de SMS para ver o resultado. Tenho certeza de que você já consegue imaginar todas as possibilidades incríveis e os casos de uso desse novo conhecimento. Você pode integrar essa filtragem de spam a softwares de RH, chatbots, atendimento ao cliente e qualquer outro aplicativo baseado em mensagens.
Tem alguma dúvida ou quer compartilhar o que está criando?
Inscreva-se no Boletim Informativo para Desenvolvedores
Siga-nos no X (antigo Twitter) para ficar por dentro das novidades
Assista aos tutoriais no nosso canal do YouTube
Conecte-se conosco na página de desenvolvedores da Vonage no LinkedIn
Fique conectado e acompanhe as últimas notícias, dicas e eventos para desenvolvedores.
Compartilhar:
Aboze Brain John é analista de negócios de tecnologia na Axa Mansard. Ele possui experiência em ciência de dados e análise de dados, pesquisa de produtos e redação técnica. Brain tem atuado em projetos completos de análise de dados, abrangendo desde a coleta, exploração, transformação/preparação e modelagem de dados até a obtenção de insights de negócios úteis, além de exercer liderança em conhecimento.