Preços de carros com IA
A indústria de compra e venda de carros usados é um mercado dinâmico, mas suscetível a golpes. Prever preços de carros é uma tarefa difícil e exige conhecimento especializado. Ao tentarmos vender ou comprar um carro, nunca sabemos se o preço negociado foi mesmo bom. Muitas revendedoras da indústria de veículos utilizam certificações de qualidade para promover seus produtos e determinar os preços que elas estão dispostas a pagar. Porém, obter uma certificação é um processo caro e demorado que requer a avaliação realizada por especialistas humanos.
Portanto, para o mercado de compra e venda de carros usados, seria interessante que o preço justo de um carro pudesse estar facilmente correlacionado com as suas características. Felizmente, a inteligência artificial (IA) pode nos ajudar nessas horas. Nesse post, usaremos a regressão linear, uma técnica simples de machine learning, para desenvolver um modelo que prevê o preço de carros rapidamente.
O Objetivo do Modelo
Partiremos de um conjunto de dados contendo detalhes de carros, como tipo de combustível, ano de fabricação, especificações do motor, etc. O conjunto também inclui os preços dos carros. Nosso objetivo é criar um modelo de machine learning usando regressão linear para prever o preço de carros com base em suas características.
O Conjunto de Dados
Utilizaremos um conjunto de dados contendo características e preços de carros. O conjunto está disponível para download gratuitamente no site do Kaggle nesse link. Ele possui cerca de 100 mil dados de carros para várias marcas. Utilizaremos apenas os dados para carros da marca Ford.
Os dados são da Inglaterra e possuem os seguintes atributos: modelo (model), ano de fabricação (year), preço (price), transmissão (transmission), quilometragem (mileage), tipo de combustível (fuelType), imposto (tax), consumo (mpg) e tamanho do motor (engineSize).
Bibliotecas
Utilizaremos várias bibliotecas típicas de machine learning e ciência de dados:
Início do Código
Num código Python, importamos os pacotes que serão usados:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.preprocessing import StandardScaler, LabelEncoder
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error
import warnings
warnings.filterwarnings('ignore')
Os dados precisam ser abertos com Pandas.
filename = 'data/ford.csv'
df = pd.read_csv(filename)
Antes de implementar o modelo, teremos que realizar a análise e pré-processamento dos dados.
Verificação dos Dados
Um dos primeiros passo para a implementação de qualquer modelo de machine learning é a verificação do conjunto de dados. Iniciaremos essa verificação imprimindo alguns exemplos do início e fim do conjunto.
print(df.head())
# resultados:
# model year price transmission mileage fuelType tax mpg engineSize
# 0 Fiesta 2017 12000 Automatic 15944 Petrol 150 57.7 1.0
# 1 Focus 2018 14000 Manual 9083 Petrol 150 57.7 1.0
# 2 Focus 2017 13000 Manual 12456 Petrol 150 57.7 1.0
# 3 Fiesta 2019 17500 Manual 10460 Petrol 145 40.3 1.5
# 4 Fiesta 2019 16500 Automatic 1482 Petrol 145 48.7 1.0
print(df.tail())
# resultados:
# model year price transmission mileage fuelType tax mpg engineSize
# 17960 Fiesta 2016 7999 Manual 31348 Petrol 125 54.3 1.2
# 17961 B-MAX 2017 8999 Manual 16700 Petrol 150 47.1 1.4
# 17962 B-MAX 2014 7499 Manual 40700 Petrol 30 57.7 1.0
# 17963 Focus 2015 9999 Manual 7010 Diesel 20 67.3 1.6
# 17964 KA 2018 8299 Manual 5007 Petrol 145 57.7 1.2
Os resultados obtidos indicam que possuímos dados numéricos e categóricos. O conjunto de dados com os preços de carros possui mais de 17 mil dados. Além dos preços, o conjunto possui oito atributos que serão usados no modelo.
A função dtypes() mostra os tipos de dados presentes no dataset, o que é importante para determinar alguns procedimentos de pré-processamento.
print(df.dtypes())
# resultados
# model object
# year int64
# price int64
# transmission object
# mileage int64
# fuelType object
# tax int64
# mpg float64
# engineSize float64
# dtype: object
Os dados do tipo object terão que ser tratados posteriormente, pois eles são categóricos.
Verificação de dados ausentes e duplicados
Também precisamos verificar a presença de dados faltantes.
print(df.isnull().sum())
# resultados:
# model 0
# year 0
# price 0
# transmission 0
# mileage 0
# fuelType 0
# tax 0
# mpg 0
# engineSize 0
# dtype: int64
O conjunto de dados não possui nenhum valor faltante.
Outro fator que precisa ser verificado no conjunto de dados é a presença de dados duplicados. Os valores duplicados serão removidos se forem encontrados.
print(df.duplicated().sum())
# resultado: 154
df.drop_duplicates()
Acima, encontramos 154 dados duplicados. Eles foram removidos com o método drop_duplicate() do Pandas.
Análise Estatística Básica
Em termos de análise estatística, o primeiro passo sempre é obter uma pequena descrição dos dados com Pandas.
df.describe()
# resultados
# year price mileage tax mpg engineSize
# count 17965.000000 17965.000000 17965.000000 17965.000000 17965.000000 17965.000000
# mean 2016.866574 12279.756415 23363.630504 113.334539 57.906991 1.350827
# std 2.050346 4741.382606 19472.114690 62.010438 10.125977 0.432371
# min 1996.000000 495.000000 1.000000 0.000000 20.800000 0.000000
# 25% 2016.000000 8999.000000 9987.000000 30.000000 52.300000 1.000000
# 50% 2017.000000 11291.000000 18243.000000 145.000000 58.900000 1.200000
# 75% 2018.000000 15299.000000 31064.000000 145.000000 65.700000 1.500000
# max 2060.000000 54995.000000 177644.000000 580.000000 201.800000 5.000000
A função nunique() do Pandas é excelente para mostrar quantas ocorrências temos para cada recurso do dataset.
df_unique = []
for feature in features:
df_unique.append((f'{feature} ---> {df[feature].nunique()}'))
print(df_unique)
# resultados
# ['model ---> 23', 'year ---> 23', 'price ---> 3511', 'transmission ---> 3', 'mileage ---> 13528', 'fuelType ---> 5', 'tax ---> 35', 'mpg ---> 90', 'engineSize ---> 16']
Após essas verificações, sabemos que conjunto de dados abrange quase 18000 carros de 23 modelos diferentes. Cada carro possui um conjunto único de atributos.
Faixa de 💰 preço:
Preço Min: 495.00 libras.
Preço Max: 54995.00 libras.
O preço médio do carro é de cerca de £ 12279.75.
Análise Exploratória dos Dados (EDA)
Para a análise exploratória de dados, faremos os gráficos kde e boxplot para as variáveis numéricas. Esses gráficos fornecem insights importantes sobre as distribuições dos dados e sobre a presença de outliers.
#PLOT VARIÁVEIS NUMÉRICAS
features = list(df.select_dtypes(include=['float', 'int']).columns)
features.remove('price')
fig, ax = plt.subplots(len(features), 2, figsize=(9, 11))
for i in range(len(features)):
sns.kdeplot(ax=ax[i,0], x=features[i], data=df, fill = True, color='lightskyblue')
sns.boxplot(ax=ax[i,1], x=features[i], data=df, fill = True, color='lightskyblue')
fig.tight_layout(pad=1)
plt.show()
Os gráficos são mostrados abaixo.

Há muitos outliers especialmente para os recursos de ano de fabricação (year) e quilometragem (mileage). A distribuição de dados é desigual e a maioria deles está com inclinação para o lado, em vez de uma distribuição gaussiana.
Também é importante analisar a distribuição dos preços no conjunto de dados com um histograma.
fig, axes = plt.subplots()
sns.histplot(data=df['price'], bins=20, kde=True, fill=True)
plt.title('Distribution of Price')
fig.tight_layout()
plt.show()

Análise de Correlações
Em termos de técnicas de visualizações, uma das mais importantes é a análise de correlações. Ela pode ser feita com um heatmap usando a biblioteca Seaborn. Essa análise verifica as correlações entre os atributos numéricos do conjunto de dados.
correlation = df[df.select_dtypes(include=['float', 'int']).columns].corr()
fig, ax = plt.subplots(figsize=(6, 6))
sns.heatmap(correlation, annot=True)
ax.set_xticklabels(ax.get_xticklabels(), rotation=45)
ax.set_title('Heatmap', weight='bold')
fig.tight_layout()
plt.show()
Abaixo veja o heatmap obtido indicando correlações principalmente do preço com o ano de fabricação dos carros, a taxa de imposto e o tamanho do motor. Existem também correlações negativas. As mais importantes são entre o preço dos carros e sua quilometragem e consumo.

Variáveis Categóricas
Obviamente, além das variáveis numéricas, precisamos analisar as relações entre os preços de carros e as variáveis categóricas do conjunto de dados. Elas são: modelo, transmissão e tipo de combustível. O código para plotá-las é mostrado abaixo.
features = list(df[df.select_dtypes(exclude=[float]).columns])
for feature in features:
if df[feature].dtype == object:
sns.catplot(y='price',x=feature,data= df.sort_values('price',ascending=False),kind='boxen',height=5, aspect=3, palette='rainbow')
plt.ylabel('Price (£)', weight='bold')
plt.xlabel(f'{feature}'.title(), weight='bold')
sns.despine()
plt.xticks(rotation=90)
plt.tight_layout()
plt.show()
E aqui estão os gráficos obtidos.



Novamente vemos a presença de outliers. Essa analise também revela que a distribuição de dados para as variáveis categóricas é desigual.
Remoção de Outliers e Engenharia de Recursos
Com base na análise realizada, faremos o pré-processamento dos dados, nos concentrando em especial na remoção de outliers. Em seguida, faremos a engenharia de recursos. Para isso, usaremos a biblioteca Scikit-learn. Ela também será usada posteriormente para implementar o modelo de regressão linear. Portanto, faremos as importações necessárias:
from sklearn.preprocessing import LabelEncoder, MinMaxScaler
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import r2_score
O pré-processamento inclui a remoção dos valores extremos encontrados em vários atributos dos dados. Antes, criamos uma cópia dos dados para criar um novo conjunto de dados limpos (clean_data):
clean_data = df.copy()
clean_data = clean_data[clean_data['year'] >= 2000]
clean_data = clean_data[clean_data['year'] < 2024]
clean_data = clean_data[clean_data['mileage'] <= 70000]
clean_data = clean_data[clean_data['mpg'] <= 100]
clean_data = clean_data[clean_data['tax'] <= 200]
clean_data['year'] = 2024 - clean_data['year']
No código acima, além da remoção de outliers, transformamos o formato do ano de fabricação para idade dos carros (linha 9).
Em seguida, realizamos a conversão dos dados categóricos usando o método LabelEncoder() do Scikit-learn.
encoder = LabelEncoder()
clean_data['model'] = encoder.fit_transform(clean_data['model'])
clean_data['transmission'] = encoder.fit_transform(clean_data['transmission'])
clean_data['fuelType'] = encoder.fit_transform(clean_data['fuelType'])
Treinamento do Modelo para Prever Preços de Carros
A implementação do modelo em si é simples. Primeiro, separamos a variável y que o modelo deve aprender a fitar.
X = clean_data.drop(['price'], axis=1)
y = clean_data['price']
scaler = MinMaxScaler()
X = scaler.fit_transform(X)
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42)
Em seguida, normalizamos os dados do conjunto X com MinMaxScaler().
scaler = MinMaxScaler()
X = scaler.fit_transform(X)
Depois, criamos os conjuntos de treinamento e teste.
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42)
Por fim, implementamos o modelo de regressão linear e realizamos o treinamento.
lin_reg = LinearRegression()
lin_reg.fit(X_train, y_train)
y_pred = lin_reg.predict(X_test)
Abaixo, usamos o método r2-score() para avaliar o desempenho do modelo no conjunto de teste. Seu score foi de 0.67, o que não é um resultado excelente.
r2 = r2_score(y_pred, y_test)
print('R2 Score:', r2)
# Resultado
# R2 Score: 0.6728690180086927
Treinamento de um Modelo Melhor
Como o resultado obtido não foi dos melhores, precisamos melhorar o modelo. Várias estratégias podem ser usadas para isso incluindo mudar o algoritmo (regressão linear), alterar a engenharia de recursos ou a remoção de outliers. Usaremos uma modificação dos recursos com o método PolynomialFeatures().
from sklearn.preprocessing import PolynomialFeatures
poly = PolynomialFeatures(3)
X_train_poly = poly.fit_transform(X_train)
X_test_poly = poly.transform(X_test)
lin_reg.fit(X_train_poly, y_train)
y_pred = lin_reg.predict(X_test_poly)
r2 = r2_score(y_pred, y_test)
print('R2 Score:', r2)
# resultados
# R2 Score: 0.8408565120275974
Veja também:
O que é machine learning (aprendizado de máquina)?
Como machine learning (aprendizado de máquina) funciona?
Como machine learning (aprendizado de máquina) aprende?
Como implementar um modelo de machine learning?
Como escolher um bom modelo de machine learning?
Classificação e regressão em machine learning
O que é conjunto de dados (dataset) em machine learning?
Onde conseguir conjuntos de dados para machine learning?
Salve localmente conjuntos de dados para machine learning
Pré-processamento de dados em machine learning
Regressão Linear e Machine Learning
Conjuntos de treinamento e teste em machine learning
Função de perda em machine learning
Scikit-learn para machine learning
Matrizes de Confusão em Machine Learning
Floresta aleatória com Scikit-learn
Detecção de anomalias com Isolation Forest
Encontrou algum erro ou quer fazer uma sugestão? Por favor, entre em contato usando nosso formulário de contatos.