[PYTHON] Amateur-Vermarkter für maschinelles Lernen forderten Kaggles Hauspreise heraus (Teil 1)

Es ist ungefähr ein halbes Jahr her, seit ich im Januar dieses Jahres angefangen habe, Python und maschinelles Lernen zu studieren.

Ich begann mit einem grundlegenden Verständnis der Grammatik und kopierte dann Data Engineering und Modellbildung, aber jetzt wollte ich versuchen, was ich selbst tun konnte, also versuchte ich es mit House Prices, einem einführenden Teil von Kaggle.

Da dies der erste Beitrag eines Amateurs für maschinelles Lernen ist, würde ich es begrüßen, wenn Sie Ihre Reißzähne aufgrund der Kindlichkeit des Textes und mangelnden Wissens in gewissem Maße zurückziehen könnten und wenn es Fehler gibt, geben Sie uns bitte einen Kommentar wie das Kauen mit Milchzähnen.

Dieser Beitrag richtet sich an "nicht tiefgreifende Kenntnisse in Technik und Programmierung" und "Anfänger innerhalb eines Jahres nach Beginn des maschinellen Lernens". Wir führen keine komplizierte Datenverarbeitung oder Modellkonstruktion durch, sondern fordern mit der grundlegenden Methodik heraus, dass die Küken endlich wegfliegen. Ich hoffe, dass diejenigen, die gerade die Grundlagen des maschinellen Lernens verstanden haben, es als Referenz verwenden können, wenn sie Daten verarbeiten und Modelle selbst erstellen. Lassen Sie uns die Immobilienpreise angehen Einer der Wettbewerbe von Kaggle ist das Problem der Vorhersage der Immobilienpreise. Dies ist das sogenannte Regressionsproblem. Die Themen sind leicht zu verstehen und die Menge an Daten und Funktionen ist nicht so groß. Daher ist es ein perfektes Thema für Kaggle-Anfänger. https://www.kaggle.com/c/house-prices-advanced-regression-techniques/overview!

Schauen wir uns die Daten an

Lesen wir zunächst die Trainingsdaten und Testdaten.


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")

Mit pd.set_option können Sie die maximale Anzahl der in einem DataFrame angezeigten Spalten und Zeilen auf eine beliebige Anzahl erhöhen. Wenn der DataFrame viele Spalten oder Zeilen enthält, werden einige davon ausgeblendet. Wenn Sie sie jedoch anzeigen möchten, ohne sie wegzulassen, wird empfohlen, sie festzulegen.

Trainingsdaten anzeigen.


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

Hier wird nur ein Teil davon angezeigt, aber als grober Eindruck

・ Numerische Werte (kontinuierliche Variablen) und Zeichen (Kategorievariablen) werden gemischt. ・ Es fehlt eine Variable ・ Der Maßstab der Größe unterscheidet sich auch zwischen numerischen Werten.

Es war so.

Es wird empfohlen, dass Sie zu diesem Zeitpunkt eine ungefähre Vorstellung von der Definition jeder Variablen haben. In data_description.txt befindet sich eine Liste mit Variablendefinitionen. Bitte lesen Sie diese, es sei denn, Sie sind eine Person, die auf Englisch einen anaphylaktischen Schock auslöst.

Danach überprüfte ich eine Liste der Variablen, bei denen Werte fehlten.


train.isnull().sum()

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

Außerdem fehlte es in etwa einem Dutzend Funktionsmengen. Hier beschränken wir die Spalte auf das Ausmaß, in dem die Spalte mit dem fehlenden Wert vollständig erkannt wird, und führen die ergänzende Verarbeitung später durch.

Oh, es ist besser, die Trainingsdaten vor der Datenverarbeitung in erklärende Variablen und objektive Variablen zu unterteilen. Außerdem ist die "ID" der Trainingsdaten für die Verarbeitung nicht erforderlich. Löschen Sie sie daher.


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

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

Vergessen Sie nicht, axis = 1 anzugeben, wenn Sie unnötige Spalten mit drop löschen.

Verarbeiten wir kategoriale Variablen

Als nächstes folgt der Konvertierungsprozess von Kategorievariablen.

Es gibt zwei Arten von Variablen in den Trainingsdaten, kategoriale Variablen und kontinuierliche Variablen, aber zuerst werden wir die kategorialen Variablen verarbeiten.

Beispielsweise sind MSZoning (A, C, FV ..) und LotShape (Reg, IR1 ..) kategoriale Variablen.

Um das Modell zu erstellen, muss es durch eine Zahl ersetzt werden, die keine Bedeutung für die Größe hat. Wenden Sie daher einen Beschriftungscodierer an, um es in einen numerischen Wert umzuwandeln. (ZB Kleidergröße: S, M, L → 1,2,3)

Erstellen Sie eine schreckliche Liste von Variablen mit einem weißen Auge.

Übrigens wird in der letzten Zeile jede Variable von astype (str) in eine Zeichenfolge konvertiert. Wenn Sie dies jedoch nicht tun, wird der folgende Fehler ausgegeben. Seien Sie also vorsichtig. 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))

Was denken Sie? Ich denke, dass der Wert von MSZoning durch Anwenden des Label-Encoders von RL auf 3 konvertiert wird.

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

Lassen Sie uns für alle Fälle den eindeutigen Wert von MSZoning überprüfen.


train_X["MSZoning"].unique()

array([3, 4, 0, 1, 2]) Sie können sehen, dass jeder Wert wie RM und RL fest in numerischen Werten codiert ist. Ich denke, dass andere kategoriale Variablen auf die gleiche Weise konvertiert werden, also überprüfen Sie es bitte.

Füllen wir die fehlenden Werte aus

Als nächstes werden fehlende Werte vervollständigt. Es fehlen sowohl kategoriale als auch kontinuierliche Variablen, daher werden wir jede einzelne verarbeiten.

Lassen Sie uns die fehlenden Werte unten noch einmal überprüfen.

train.isnull().sum()

Dann wurde der fehlende Wert gegenüber dem vorherigen Zeitpunkt stark reduziert. Dies liegt daran, dass der Beschriftungscodierer den fehlenden Wert durch eine bestimmte Nummer ersetzt hat. Ist es für einen Moment in Ordnung? Ich dachte, aber ich denke, dass es kein Problem gibt, weil der fehlende Wert selbst identifiziert wird.

Es fehlten drei Werte: LotFrontage, MasVnrArea und GarageYrBlt.

Abschließend ・ Lot Frontage ist der Durchschnittswert ・ MasVnrArea ist der Medianwert ・ GarageYrBlt ist 0 Ergänzt mit.

Zunächst dachte ich in Bezug auf die ersten beiden, dass es besser wäre, den Medianwert oder den Durchschnittswert zu ergänzen, als die fehlenden Zeilen auszuschließen, und überprüfte daher vorerst den Verteilungsstatus der Daten.


#Die Größe des Rahmens, in den das Diagramm eingefügt werden soll
plt.figure(figsize=(10, 4))

#Wird auf der linken Seite des 1-mal-2-Rahmens platziert
plt.subplot(1,2,1)
plt.hist(train["MasVnrArea"] , bins=30 , label="MasVnrArea")
plt.legend(loc="best")
print("[MasVnr Area] Durchschnittswert:{:.2f}Median:{:}".format(train["MasVnrArea"].mean() , train["MasVnrArea"].median()))

#Wird auf der rechten Seite des 1-mal-2-Rahmens platziert
plt.subplot(1,2,2)
plt.hist(train["LotFrontage"] , bins=30 , label="LotFrontage")
print("[Lot Frontage] Durchschnittswert:{:.2f}Median:{:}".format(train["LotFrontage"].mean() , train["LotFrontage"].median()))
plt.legend(loc="best")
グラフ.PNG In Bezug auf das Diagramm sowie die Median- und Mittelwerte unterscheidet sich MasVnrArea erheblich von den Median- und Mittelwerten. Ich dachte, wenn ich den Durchschnittswert setze, obwohl die meisten Werte 0 sind, würde er auf den Extremwert gezogen, also entschied sich MaxVnrArea, den Medianwert zu setzen. LotFrontage ist für beide Werte ungefähr gleich, aber vorerst habe ich den Durchschnittswert eingegeben.
#Median-Ergänzung
train_X["MasVnrArea"] = train_X["MasVnrArea"].fillna(train_X["MasVnrArea"].median())

#Durchschnittswertkomplement
train_X["LotFrontage"] = train_X["LotFrontage"].fillna(train_X["LotFrontage"].mean())

Schließlich, GarageYrBlt, ist dies das Baujahr. Vielleicht hat der fehlende Datensatz keine Garage, was bedeutet, dass andere Garage-bezogene Variablen durch Zahlen ersetzt wurden, die ursprünglich NaN waren? Ich werde die Bestätigungsmethode weglassen, aber es scheint so.

Selbst wenn GarageYrBlt den fehlenden Wert auf "0" setzt, erkennt die KI, dass "Oh, dieser Typ hat keine Garage" im Vergleich zu anderen Variablen im Zusammenhang mit Garage.

Ersetzen Sie unter der Hypothese durch 0.

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

Jetzt haben alle Variablen keine fehlenden Werte und können durch Zahlen ersetzt werden. Jetzt kann ich es in ein Modell für maschinelles Lernen einfügen, aber ich dachte irgendwie.

"Gibt es nicht zu viele Variablen? Soll ich es eingrenzen?"

Also werde ich versuchen, die Variablen einzugrenzen.

Lassen Sie uns die Variablen eingrenzen

Wenn diesmal der Korrelationskoeffizient zwischen SalePrice, der Zielvariablen, und jeder Variablen über einem bestimmten Wert liegt, wird diese Variable übernommen.

Zuerst wollte ich einen schnellen visuellen Überblick über die Korrelation bekommen, also werde ich die Seaborn Heatmap verwenden.


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

Die Größe der Heatmap wird durch figsize festgelegt. Für jedes Argument ist corr () die Methode zur Ausgabe des Korrelationskoeffizienten, cmap ist die Farbe der Wärmekarte und annot ist, ob der Korrelationskoeffizient für jede Zelle ausgegeben werden soll oder nicht. ヒートマップ.PNG Sie können den Korrelationskoeffizienten zwischen SalePrice und jeder Variablen in der Spalte ganz rechts sehen, aber auf den ersten Blick scheinen Variablen von 0,3 oder mehr wichtig zu sein. Geben Sie also die Variablen mit großem Korrelationskoeffizienten in absteigender Reihenfolge aus und nehmen Sie nur die Variablen von 0,3 oder mehr auf.

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

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

Wenn Sie in absteigender Reihenfolge ausgeben, wird es in diesem Format vorliegen, aber es scheint, dass Sie es als DataFrame-Typ festlegen müssen, um den Variablennamen zu extrahieren.


#In Datenrahmen konvertieren und Spaltennamen auflisten
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]

Der Datensatz (Variable + Wert) mit einem bestimmten Korrelationskoeffizienten wird durch df.query in der zweiten Zeile extrahiert. Der Grund, warum 1 oder weniger in der Bedingung enthalten ist, besteht darin, den Verkaufspreis herauszuziehen. Durch Extrahieren des Variablennamens, der der Index in df.index in der dritten Zeile ist, und Ersetzen durch ein Array können Sie ein Array erstellen, das nur Variablen mit einem Korrelationskoeffizienten von 0,3 oder mehr enthält. Ändern Sie in der 4. Zeile die Trainingsdaten in den Datenrahmen nur mit den obigen Variablen.

Schließlich ist die Verarbeitung der Trainingsdaten abgeschlossen. Wir dürfen jedoch die Verarbeitung der Testdaten nicht vergessen.

Verarbeiten wir die Testdaten

Übrigens ist mir aufgefallen, dass, wenn ich vergessen habe, die Testdaten zu verarbeiten und das Modell so zu machen, wie es war, ein Fehler aufgetreten ist und ich die Testdaten dort nicht verarbeitet habe. Dies ist die erste Verzweiflung.

Sollte es jedoch nicht auf die gleiche Weise wie die Trainingsdaten verarbeitet werden? Ich dachte, und wenn ich es fast so verarbeite, wie es war, wäre es wieder ein Fehler. Dies ist meine zweite Verzweiflung.

Warum! !! !! !! !!

Als ich den Fehler betrachtete, schien es, dass er auf den fehlenden Wert zurückzuführen war, also überprüfte ich ruhig den fehlenden Wert in den Testdaten.

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

Anscheinend sind die Trainingsdaten und die Anzahl der fehlenden Werte und fehlenden Variablen unterschiedlich.

Hmm ... Es ist schwer für Anfänger, aber lassen Sie uns eins nach dem anderen damit umgehen.

Der Anfang ist der gleiche Prozess wie die Trainingsdaten.

#ID aus den Testdaten entfernen
test_X = test.drop(["Id"] , axis=1)

#Wenden Sie den Beschriftungscodierer auf die Kategorievariable an
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))

Als nächstes werden fehlende Werte verarbeitet.

Auch nach der Etikettencodierung werden fehlende Werte in kontinuierlicheren Variablen als in Trainingsdaten angezeigt.

Füllen wir die fehlenden Werte auf die gleiche Weise wie zuvor aus.

#Durchschnittswertkomplement
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 Ergänzung
test_X["GarageYrBlt"] = test_X["GarageYrBlt"].fillna(0)

Grenzen Sie schließlich wie bei den Trainingsdaten die Variablen mit einem Korrelationskoeffizienten von 0,3 oder mehr ein. column_needed ist ein Array von Variablen mit einem Korrelationskoeffizienten von 0,3 oder mehr, die während der Trainingsdatenverarbeitung erstellt werden.


test_X = test_X[columns_needed]

Die Testdaten sind ebenfalls vollständig. Es ist endlich Zeit, das Modell zu bauen.

Lassen Sie uns ein Modell bauen

Diesmal habe ich ein Modell in Random Forest gemacht. Was ist zufälliger Wald? Ich werde in diesem Artikel nicht auf die Details eingehen, aber der Grund, warum ich mich dafür entschieden habe, ist, dass es genauer zu sein scheint als lineare Regression und SVM, und ich kann es selbst machen.

Ich verstehe die theoretische Geschichte des Modells, aber ... nun, Anfänger sind so.

Lass es uns machen.

Erstellen Sie nach dem Importieren der zufälligen Gesamtstruktur eine Liste mit Parametern für eine Rastersuche.

#Erstellen Sie ein Modell in einer zufälligen Gesamtstruktur
from sklearn.ensemble import RandomForestRegressor
rf = RandomForestRegressor()

#Rastersuche nach Parametern
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]}

Ich möchte, dass Sie für die Rastersuche auf andere Artikel verweisen, aber wenn Sie grob erklären, sagten Sie: "Das beste Modell wird erstellt, indem Sie die entsprechende Kombination von Parametern aus mehreren Parametern auswählen."

Ich habe versucht, die detaillierten Parameter auszuwählen, die optimiert werden müssen, während ich mir die Hilfeseite von sklearn angesehen habe. https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestRegressor.html

Erstellen Sie ein Modell durch Rastersuche mithilfe der obigen Parameterliste.


#Modellerstellung mit Rastersuche
clf = GridSearchCV(rf , parameters , scoring="neg_root_mean_squared_error" , cv=5)
clf.fit(train_X , train_y)

#Holen Sie sich die besten Parameter
print(clf.best_estimator_)

Geben Sie für das Argument von GridSearchCV RMSE, den Bewertungsindex von Kaggle, für die Bewertung und 5 für CV an, dh die Anzahl der Unterteilungen für die Schnittpunktüberprüfung. Jedes wurde unter Bezugnahme auf Folgendes festgelegt, aber beachten Sie, dass dies nicht immer der geeignete Parameter ist. 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)

Die Ausgabe dauert einige Zeit, aber ich konnte die besten Parameter sicher ermitteln. Ich möchte endlich die Testdaten vorhersagen.

Testdaten vorhersagen

Ich bin endlich da. Lassen Sie uns abschließend die Testdaten vorhersagen.

pred_y = clf.predict(test_X)
pred_y

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

Es wurde sicher ausgegeben. Danach werde ich die Daten zur Einreichung in der Hoffnung machen, dass diese Vorhersagedaten eine hohe Punktzahl ergeben können.

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

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

Sie haben jetzt eine Datei namens submit.csv in Ihrem lokalen.

Beachten Sie übrigens, dass, wenn der Index auf True gesetzt ist, auch unnötige Indexnummern in der Übermittlungsdatei erstellt werden und nicht dem für die Übermittlung erforderlichen Format entsprechen.

Lassen Sie uns die Punktzahl überprüfen

Klicken Sie hier für die Ergebnisse. score1.PNG Die Punktzahl ist 0,15453 und das Ranking ist 3.440. (Etwa 67% der Gesamtzahl)

Nein, es ist niedrig ... Ich habe das große Erfolgserlebnis, dass ich die Datenverarbeitung und die Modellkonstruktion selbstständig bewältigen konnte, aber wenn ich mir die Ergebnisse ansehe, bin ich immer noch enttäuscht.

Jedoch···

Danach wurde ich nach verschiedenen Versuchen und Fehlern auf den 2.074. Platz mit einer Punktzahl von 0,13576 eingestuft. (Etwa 40% der Gesamtmenge)

Ich möchte im zweiten Teil darüber schreiben, welche Art von Verarbeitung danach durchgeführt wurde.

Recommended Posts

Amateur-Vermarkter für maschinelles Lernen forderten Kaggles Hauspreise heraus (Teil 1)
Vorhersage der Immobilienpreise (maschinelles Lernen: zweite Hälfte) ver1.1
Herausforderung Kaggle [Hauspreise]
Maschinelles Lernen Kaninchen Herausforderung
Ist es möglich, mit Aktienkursvorhersage durch maschinelles Lernen zu essen [Maschinelles Lernen Teil 1]
Vorhersage des Strombedarfs durch maschinelles Lernen Teil 2
[Python] Wenn ein Amateur mit dem maschinellen Lernen beginnt
EV3 x Pyrhon Maschinelles Lernen Teil 3 Klassifizierung
Maschinelles Lernen
Maschinelles Lernen eines jungen Ingenieurs Teil 1
Klassifizierung von Gitarrenbildern durch maschinelles Lernen Teil 1
Maschinelles Lernen beginnend mit Python Personal Memorandum Part2
Maschinelles Lernen beginnend mit Python Personal Memorandum Part1
EV3 x Pyrhon Maschinelles Lernen Teil 1 Umgebungskonstruktion
EV3 x Python Maschinelles Lernen Teil 2 Lineare Regression
[Maschinelles Lernen] Überwachtes Lernen mithilfe der Kernel-Dichteschätzung Teil 3
Maschinelles Lernen eines jungen Ingenieurs Teil 2
Klassifizierung von Gitarrenbildern durch maschinelles Lernen Teil 2