[PYTHON] Un spécialiste du marketing amateur en apprentissage automatique a contesté les prix des maisons de Kaggle (partie 1)

Cela fait environ six mois que j'ai commencé à étudier Python et l'apprentissage automatique vers janvier de cette année.

J'ai commencé avec une compréhension de base de la grammaire, puis j'ai copié l'ingénierie des données et la construction de modèles, mais maintenant je voulais essayer ce que je pouvais faire par moi-même, alors j'ai essayé House Prize, qui est une partie introductive de Kaggle.

De plus, puisqu'il s'agit du premier message d'un amateur d'apprentissage automatique, j'apprécierais que vous puissiez retirer vos crocs dans une certaine mesure en raison de l'enfantillage du texte et du manque de connaissances, et s'il y a des erreurs, veuillez commenter comme si vous mordiez avec des dents de lait.

introduction

Cet article est destiné aux "connaissances non approfondies de l'ingénierie et de la programmation" et aux "débutants dans l'année suivant le début de l'apprentissage automatique".

Nous n'effectuons pas de traitement de données compliqué ou de construction de modèles, mais contestons avec la méthodologie de base que les poussins ont finalement commencé à s'envoler.

J'espère que ceux qui viennent de comprendre les bases de l'apprentissage automatique pourront l'utiliser comme référence lors du traitement des données et de la construction de modèles par eux-mêmes.

Travaillons sur les prix des logements

L'un des concours organisés par Kaggle est le problème de la prévision des prix des logements. C'est le soi-disant problème de régression. Les sujets sont faciles à comprendre et la quantité de données et de fonctionnalités n'est pas si grande, c'est donc un sujet parfait pour les débutants de Kaggle. https://www.kaggle.com/c/house-prices-advanced-regression-techniques/overview!

Regardons les données

Tout d'abord, lisons les données d'entraînement et les données de test.


read_data.ipynb
import pandas as pd
 
pd.set_option("display.max_columns" , 200)
pd.set_option("display.max_rows" , 100000)

train = pd.read_csv("train.csv")
test = pd.read_csv("test.csv")

Vous pouvez augmenter le nombre maximal de colonnes et de lignes affichées dans un DataFrame à n'importe quel nombre avec pd.set_option. Par défaut, s'il existe de nombreuses colonnes ou lignes dans le DataFrame, certaines d'entre elles seront masquées, mais si vous souhaitez les afficher sans les omettre, il est recommandé de les définir.

Affichez les données d'entraînement.


train.head()
Id MSSubClass MSZoning LotFrontage ...
1 60 RL 65.0 ...
2 20 RL 80.0 ...
3 60 RL 68.0 ...

Seule une partie est affichée ici, mais comme une impression approximative,

・ Les valeurs numériques (variables continues) et les caractères (variables de catégorie) sont mélangés. ・ Certaines variables manquent ・ L'échelle de la taille est différente même entre les valeurs numériques.

C'était comme ça.

Il est recommandé d'avoir une idée approximative de la définition de chaque variable à ce stade. Il existe une liste de définitions de variables dans data_description.txt, veuillez donc la lire sauf si vous êtes une personne qui induit un choc anaphylactique en anglais.

Après cela, j'ai vérifié une liste des variables qui avaient des valeurs manquantes.


train.isnull().sum()

Id 0 MSSubClass 0 MSZoning 0 LotFrontage 259 LotArea 0 Street 0 Alley 1369 ...

De plus, il manquait dans une douzaine de quantités de caractéristiques. Ici, nous limiterons la colonne dans la mesure où la colonne avec la valeur manquante est complètement reconnue, et effectuerons le traitement complémentaire ultérieurement.

Oh, il est préférable de diviser les données d'entraînement en variables explicatives et en variables objectives avant le traitement des données. De plus, l '"Id" des données d'apprentissage n'est pas nécessaire pour le traitement, supprimez-le.


train_X = train.iloc[:,:-1]
train_y = train["SalePrice"]

train_X = train_X.drop(["Id"] , axis=1)

N'oubliez pas de spécifier axis = 1 lors de la suppression des colonnes inutiles avec drop.

Traitons les variables catégorielles

Vient ensuite le processus de conversion des variables de catégorie.

Il existe deux types de variables dans les données d'apprentissage, les variables catégorielles et les variables continues, mais nous allons d'abord traiter les variables catégorielles.

Par exemple, MSZoning (A, C, FV ..) et LotShape (Reg, IR1 ..) sont des variables catégorielles.

Afin de construire le modèle, il est nécessaire de le remplacer par un nombre qui n'a aucune signification de taille, alors appliquez un encodeur d'étiquette pour le convertir en une valeur numérique. (Par exemple, taille de vêtements: S, M, L → 1,2,3)

Créez une liste horrible de variables avec un œil blanc.

À propos, dans la dernière ligne, chaque variable est convertie en chaîne de caractères par astype (str), mais si vous ne le faites pas, l'erreur suivante sera générée, alors soyez prudent. TypeError: argument must be a string or number


from sklearn.preprocessing import LabelEncoder
le = LabelEncoder()

columns = ["MSZoning","Street","Alley","LotFrontage","Street","Alley","LotShape","LandContour","Utilities","LotConfig","LandSlope","Neighborhood","Condition1","Condition2","BldgType","HouseStyle","RoofStyle","RoofMatl","Exterior1st","Exterior2nd","MasVnrType","ExterQual","ExterCond","Foundation","BsmtQual","BsmtCond","BsmtExposure","BsmtFinType1","BsmtFinType2","Heating","HeatingQC","CentralAir","Electrical","KitchenQual","Functional","FireplaceQu","GarageType","GarageFinish","GarageQual","GarageCond","PavedDrive","PoolQC","Fence","MiscFeature","SaleType","SaleCondition"]

for col in columns:
    train_X[col] = le.fit_transform(train_X[col].astype(str))

Qu'est-ce que tu penses? Je pense que la valeur de MSZoning est convertie de RL à 3 en appliquant l'encodeur d'étiquette.

MSSubClass MSZoning LotFrontage ...
60 3 65.0 ...
20 3 80.0 ...
60 3 68.0 ...

Au cas où, vérifions la valeur unique de MSZoning.


train_X["MSZoning"].unique()

array([3, 4, 0, 1, 2]) Vous pouvez voir que chaque valeur telle que RM et RL est fermement codée en valeurs numériques. Je pense que les autres variables de catégorie sont converties de la même manière, veuillez donc la vérifier.

Remplissons les valeurs manquantes

Vient ensuite l'achèvement des valeurs manquantes. Puisqu'il manque des variables pour les variables catégorielles et les variables continues, nous traiterons chacune.

Vérifions à nouveau les valeurs manquantes ci-dessous.

train.isnull().sum()

Ensuite, la valeur manquante a été considérablement réduite par rapport à la fois précédente. En effet, le codeur d'étiquette a remplacé la valeur manquante par un nombre spécifique. Est-ce que ça va pour un moment? J'ai pensé, mais je pense qu'il n'y a pas de problème car la valeur manquante elle-même est identifiée.

Il y avait trois valeurs manquantes: LotFrontage, MasVnrArea et GarageYrBlt.

En conclusion ・ La façade du lot est la valeur moyenne ・ MasVnrArea est la valeur médiane ・ GarageYrBlt est égal à 0 Complété avec.

Tout d'abord, en ce qui concerne les deux premiers, j'ai pensé qu'il serait préférable de compléter avec la valeur médiane ou la valeur moyenne plutôt que d'exclure les lignes manquantes, j'ai donc vérifié l'état de distribution des données pour le moment.


#La taille du cadre pour mettre le graphique
plt.figure(figsize=(10, 4))

#Placé sur le côté gauche du cadre 1 par 2
plt.subplot(1,2,1)
plt.hist(train["MasVnrArea"] , bins=30 , label="MasVnrArea")
plt.legend(loc="best")
print("[MasVnr Area] Valeur moyenne:{:.2f}Médian:{:}".format(train["MasVnrArea"].mean() , train["MasVnrArea"].median()))

#Placé sur le côté droit du cadre 1 par 2
plt.subplot(1,2,2)
plt.hist(train["LotFrontage"] , bins=30 , label="LotFrontage")
print("[Lot Frontage] Valeur moyenne:{:.2f}Médian:{:}".format(train["LotFrontage"].mean() , train["LotFrontage"].median()))
plt.legend(loc="best")
グラフ.PNG En regardant le graphique et les valeurs médianes et moyennes, MasVnrArea est assez différent des valeurs médianes et moyennes. Je pensais que si je mettais la valeur moyenne même si la plupart des valeurs étaient 0, elle serait tirée à la valeur extrême, alors MaxVnrArea a décidé de mettre la valeur médiane. LotFrontage est à peu près le même pour les deux valeurs, mais pour le moment, je mets la valeur moyenne.
#Complément médian
train_X["MasVnrArea"] = train_X["MasVnrArea"].fillna(train_X["MasVnrArea"].median())

#Complément de valeur moyenne
train_X["LotFrontage"] = train_X["LotFrontage"].fillna(train_X["LotFrontage"].mean())

Enfin, GarageYrBlt, c'est l'année de construction. Peut-être que l'enregistrement qui manque n'a pas de Garage, ce qui signifie que d'autres variables liées à Garage ont été remplacées par des nombres qui étaient à l'origine NaN? Je vais omettre la méthode de confirmation, mais cela semble être le cas.

Ainsi, même si GarageYrBlt définit la valeur manquante sur "0", l'IA reconnaîtra que "Oh, ce gars n'a pas de garage" par rapport à d'autres variables liées à Garage.

Sous l'hypothèse, remplacez par 0.

train_X["GarageYrBlt"] = train_X["GarageYrBlt"].fillna(0)

Désormais, toutes les variables n'ont aucune valeur manquante et peuvent être remplacées par des nombres. Maintenant, je peux le mettre dans un modèle d'apprentissage automatique, mais j'ai en quelque sorte pensé.

"N'y a-t-il pas trop de variables? Dois-je le réduire?"

Je vais donc essayer de restreindre les variables.

Affinons les variables

Cette fois, si le coefficient de corrélation entre SalePrice, qui est la variable objective, et chaque variable est supérieur à une certaine valeur, cette variable est adoptée.

Tout d'abord, je voulais avoir un aperçu visuel rapide de la corrélation, je vais donc utiliser la carte thermique Seaborn.


plt.figure(figsize=(20,15))
sns.heatmap(train.corr() , cmap="Blues" , annot=True)

La taille de la carte thermique est définie par figsize. Pour chaque argument, corr () est la méthode de sortie du coefficient de corrélation, cmap est la couleur de la carte thermique et annot indique s'il faut ou non sortir le coefficient de corrélation pour chaque cellule. ヒートマップ.PNG Vous pouvez voir le coefficient de corrélation entre SalePrice et chaque variable en regardant la colonne la plus à droite, mais à première vue, il semble que les variables de 0,3 ou plus sont importantes. Donc, sortez les variables avec un coefficient de corrélation élevé dans l'ordre décroissant et ne prenez que les variables de 0,3 ou plus.

train.corr()["SalePrice"].sort_values(ascending=False)

SalePrice 1.000000 OverallQual 0.790982 GrLivArea 0.708624 GarageCars 0.640409 GarageArea 0.623431 ...

Si vous sortez dans l'ordre décroissant, ce sera dans ce format, mais il semble que vous deviez en faire un type DataFrame pour extraire le nom de la variable.


#Convertir en blocs de données et lister les noms de colonnes
df = pd.DataFrame(train.corr()["SalePrice"].sort_values(ascending=False))
df = df.query("0.3 <= SalePrice < 1.0")
columns_needed = np.array(df.index)
train_X = train_X[columns_needed]

L'enregistrement (variable + valeur) avec un coefficient de corrélation spécifique est extrait par df.query sur la deuxième ligne. La raison pour laquelle 1 ou moins est inclus dans la condition est de retirer le prix de vente. En extrayant le nom de la variable qui est l'index dans df.index sur la troisième ligne et en le remplaçant par un tableau, vous pouvez créer un tableau qui contient uniquement des variables avec un coefficient de corrélation de 0,3 ou plus. Sur la 4ème ligne, modifiez les données d'apprentissage en bloc de données avec uniquement les variables ci-dessus.

Enfin, le traitement des données d'apprentissage est terminé. Cependant, il ne faut pas oublier le traitement des données de test.

Traitons les données de test

En passant, j'ai remarqué que si j'oubliais de traiter les données de test et de créer le modèle tel quel, une erreur s'est produite et je n'ai pas traité les données de test là-bas. C'est le premier désespoir.

Cependant, ne devrait-il pas être traité de la même manière que les données d'entraînement? J'ai pensé, et si je le traitais presque tel quel, ce serait encore une erreur. C'est mon deuxième désespoir.

Pourquoi! !! !! !! !!

En regardant l'erreur, il semblait que cela était dû à la valeur manquante, alors j'ai calmement vérifié la valeur manquante dans les données de test.

Id 0 MSSubClass 0 MSZoning 4 LotFrontage 227 LotArea 0 Street 0 Alley 1352 ...

Apparemment, les données d'entraînement et le nombre de valeurs manquantes et de variables manquantes sont différents.

Hmm ... C'est difficile pour les débutants, mais allons-y un par un.

Le début est le même processus que les données d'entraînement.

#Supprimer l'ID des données de test
test_X = test.drop(["Id"] , axis=1)

#Appliquer l'encodeur d'étiquette à la variable de catégorie
from sklearn.preprocessing import LabelEncoder
le = LabelEncoder()

columns = ["MSZoning","Street","Alley","LotShape","LandContour","Utilities","LotConfig","LandSlope","Neighborhood","Condition1","Condition2","BldgType","HouseStyle","RoofStyle","RoofMatl","Exterior1st","Exterior2nd","MasVnrType","ExterQual","ExterCond","Foundation","BsmtQual","BsmtCond","BsmtExposure","BsmtFinType1","BsmtFinType2","Heating","HeatingQC","CentralAir","Electrical","KitchenQual","Functional","FireplaceQu","GarageType","GarageFinish","GarageQual","GarageCond","PavedDrive","PoolQC","Fence","MiscFeature","SaleType","SaleCondition"]

for col in columns:
    test_X[col] = le.fit_transform(test_X[col].astype(str))

Vient ensuite le traitement des valeurs manquantes.

Même après le codage des étiquettes, les valeurs manquantes sont visibles dans des variables plus continues que les données d'apprentissage.

Remplissons les valeurs manquantes de la même manière qu'auparavant.

#Complément de valeur moyenne
test_X["LotFrontage"] = test_X["LotFrontage"].fillna(test_X["LotFrontage"].mean())
test_X["BsmtUnfSF"] = test_X["BsmtUnfSF"].fillna(test_X["BsmtUnfSF"].mean())
test_X["BsmtFullBath"] = test_X["BsmtFullBath"].fillna(test_X["BsmtFullBath"].mean())
test_X["GarageArea"] = test_X["GarageArea"].fillna(test_X["GarageArea"].mean())
test_X["TotalBsmtSF"] = test_X["TotalBsmtSF"].fillna(test_X["TotalBsmtSF"].mean())
test_X["MasVnrArea"] = test_X["MasVnrArea"].fillna(test_X["MasVnrArea"].mean())
test_X["BsmtFinType2"] = test_X["BsmtFinType2"].fillna(test_X["BsmtFinType2"].mean())
test_X["BsmtFinSF1"] = test_X["BsmtFinSF1"].fillna(test_X["BsmtFinSF1"].mean())
test_X["BsmtFinSF2"] = test_X["BsmtFinSF2"].fillna(test_X["BsmtFinSF2"].mean())
test_X["BsmtHalfBath"] = test_X["BsmtHalfBath"].fillna(test_X["BsmtHalfBath"].mean())
test_X["GarageCars"] = test_X["GarageCars"].fillna(test_X["GarageCars"].mean())

#0 complément
test_X["GarageYrBlt"] = test_X["GarageYrBlt"].fillna(0)

Enfin, comme pour les données d'apprentissage, affinez les variables avec un coefficient de corrélation de 0,3 ou plus. column_needed est un tableau de variables avec un coefficient de corrélation de 0,3 ou plus créé lors du traitement des données d'entraînement.


test_X = test_X[columns_needed]

Les données de test sont également complètes. Il est enfin temps de construire le modèle.

Construisons un modèle

Cette fois, j'ai fait un modèle dans Random Forest. Qu'est-ce que Random Forest? Je n'entrerai pas dans les détails dans cet article, mais la raison pour laquelle je l'ai choisi est qu'il semble être plus précis que la régression linéaire et SVM, et je peux le faire moi-même.

Je comprends l'histoire théorique du modèle, mais ... eh bien, les débutants sont comme ça.

Faisons-le.

Après avoir importé la forêt aléatoire, créez une liste de paramètres pour une recherche de grille.

#Construire un modèle dans une forêt aléatoire
from sklearn.ensemble import RandomForestRegressor
rf = RandomForestRegressor()

#Grille de recherche de paramètres
from sklearn.model_selection import GridSearchCV
parameters = {"n_estimators":[10,30,50,70,100,130], 
              "criterion":["mae","mse"],
              "max_depth":[3,5,7,10,15], 
              "max_features":["auto"], 
              "random_state":[0], 
              "n_jobs":[-1]}

Je voudrais que vous vous référiez à d'autres articles pour la recherche de grille, mais si vous expliquez grossièrement, vous avez dit: "Le meilleur modèle est créé en sélectionnant la combinaison appropriée de paramètres à partir de plusieurs paramètres."

J'ai essayé de sélectionner les paramètres détaillés qui semblaient nécessiter une optimisation en consultant le site d'aide de sklearn. https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestRegressor.html

Créez un modèle par recherche de grille à l'aide de la liste de paramètres ci-dessus.


#Création de modèle avec recherche de grille
clf = GridSearchCV(rf , parameters , scoring="neg_root_mean_squared_error" , cv=5)
clf.fit(train_X , train_y)

#Obtenez les meilleurs paramètres
print(clf.best_estimator_)

Pour l'argument de GridSearchCV, spécifiez RMSE, qui est l'indice d'évaluation de Kaggle, pour la notation, et 5 pour CV, ce qui signifie le nombre de divisions pour la vérification des intersections. Chacun a été défini en fonction de ce qui suit, mais gardez à l'esprit que ce n'est pas toujours le paramètre approprié. https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.GridSearchCV.html https://scikit-learn.org/stable/modules/model_evaluation.html#scoring-parameter

RandomForestRegressor(bootstrap=True, ccp_alpha=0.0, criterion='mae', max_depth=15, max_features='auto', max_leaf_nodes=None, max_samples=None, min_impurity_decrease=0.0, min_impurity_split=None, min_samples_leaf=1, min_samples_split=2, min_weight_fraction_leaf=0.0, n_estimators=130, n_jobs=-1, oob_score=False, random_state=0, verbose=0, warm_start=False)

La sortie prend un certain temps, mais j'ai pu obtenir les meilleurs paramètres en toute sécurité. Je veux enfin prédire les données de test.

Prédire les données de test

Je suis enfin là. Enfin, prédisons les données de test.

pred_y = clf.predict(test_X)
pred_y

array([122153.44615385, 149360.57692308, 174654.18846154, ..., 160791.61538462, 106482.30769231, 236272.41923077])

Il était sorti en toute sécurité. Après cela, je ferai les données pour soumission dans l'espoir que ces données de prédiction puissent donner un score élevé.

test["SalePrice"] = pred_y
test[["Id","SalePrice"]].head()

import csv
test[["Id","SalePrice"]].to_csv("submission.csv" , index=False)

Vous avez maintenant un fichier appelé submit.csv dans votre local.

En passant, veuillez noter que si l'index est défini sur True, les numéros d'index inutiles seront également créés dans le fichier de soumission et ne correspondront pas au format requis pour la soumission.

Vérifions le score

Cliquez ici pour les résultats. score1.PNG Le score est de 0,15453 et le classement est de 3440. (Environ 67% du total)

Non, c'est faible ... J'ai un grand sentiment d'accomplissement d'avoir pu gérer seul le traitement des données et la construction de modèles, mais quand je regarde les résultats, je suis toujours déçu.

Pourtant···

Après cela, après divers essais et erreurs, j'ai été classé jusqu'à 2074e place avec un score de 0,13576. (Environ 40% du total)

Je voudrais écrire sur le type de traitement qui a été effectué après cela dans la deuxième partie.

Recommended Posts

Un spécialiste du marketing amateur en apprentissage automatique a contesté les prix des maisons de Kaggle (partie 1)
Prédire les prix des logements (apprentissage automatique: deuxième semestre) ver1.1
Challenge Kaggle [Prix de la maison]
Défi de lapin d'apprentissage automatique
Est-il possible de manger avec la prévision du cours des actions par apprentissage automatique [Machine learning partie 1]
Prédire la demande de puissance avec l'apprentissage automatique, partie 2
[Python] Lorsqu'un amateur commence l'apprentissage automatique
Classification EV3 x Pyrhon Machine Learning Partie 3
Apprentissage automatique
Mémo d'apprentissage automatique d'un ingénieur débutant Partie 1
Classification des images de guitare par apprentissage automatique Partie 1
Apprentissage automatique à partir de Python Personal Memorandum Part2
Apprentissage automatique à partir de Python Personal Memorandum Part1
EV3 x Pyrhon Machine Learning Partie 1 Construction de l'environnement
EV3 x Python Machine Learning Partie 2 Régression linéaire
[Apprentissage automatique] Apprentissage supervisé utilisant l'estimation de la densité du noyau Partie 3
Mémo d'apprentissage automatique d'un ingénieur débutant Partie 2
Classification des images de guitare par apprentissage automatique, partie 2