Dies ist Miyano (@estie_mynfire) von estie CTO. Am ersten Tag schrieb ich einen kleinen Nischeninhalt (Ich habe Pandas 'Sql Upsert ausprobiert), aber diesmal mache ich es bei estie ** "Office" Über "Prognose der fairen Miete" **.
Was die Büromiete betrifft, so ist die angebotene Miete im Gegensatz zu Wohnraum nicht so öffentlich (nur ein Drittel oder weniger der Immobilien sind in den 5 zentralen Bezirken der Stadt für die Öffentlichkeit zugänglich), und die vertraglich vereinbarte Miete ist grundsätzlich nicht verfügbar ** Es ist schwierig, korrekte Antwortdaten zu sammeln **. Unter diesen Umständen überprüfen wir bei der Schätzung der Immobilienmiete gemeinsam die Richtigkeit des Modells und berücksichtigen dabei die professionellen Augen von Büroimmobilien auf der Unternehmensseite.
Da es viele Interaktionen mit Unternehmensseiten gibt, werde ich darüber schreiben, worauf ich besonders achte und was ich mir ausgedacht habe.
Wie oben erwähnt, treten die folgenden Probleme häufiger auf, wenn wir nur mit ML-Ingenieuren entwickeln, da wir mit den Mitgliedern auf der Unternehmensseite zusammenarbeiten.
Mit Feedback von Wirtschaftsingenieuren und Erweiterung der Quelldaten Wir nehmen häufig logische Änderungen vor, z. B. das Entfernen von Eigenschaften außerhalb des Werts, das Hinzufügen von Feature-Mengen und das Ändern von Lerndaten. Wir verbessern jeden Tag, um genauere Modelle zu erstellen. Wie oben erwähnt, kann die Genauigkeit dieser Modelle jedoch nicht immer nur mit numerischen Indikatoren bewertet werden (professionelle Augen sind ebenfalls erforderlich). Ich wollte ein besseres Modell als in der Vergangenheit machen
** "Oh, wenn es vor zwei Monaten ein Modell gewesen wäre, wäre es hier ein guter Wert gewesen, aber es ist ein seltsamer Wert!" **
Was passiert oft? ~~ Die meiste Zeit bemerke ich das, wenn ich es eilig habe, also kribbele ich. ~~
Wenn Sie in einem solchen Fall sofort zum Status des vorherigen Modells zurückkehren können, können Sie die Ursache sofort untersuchen und mit hoher Geschwindigkeit in den Produktionsdaten wiedergeben.
Bei der gemeinsamen Überprüfung der Genauigkeit werden wir häufig gebeten, die Ursache zu erläutern, z. B. "Der geschätzte Wert hier, warum ist er so ein Wert?". Wenn Sie in einem solchen Fall erklären können: "Ich bin stark von diesem Funktionsumfang beeinflusst", können Sie eine aussagekräftigere Diskussion fortsetzen.
Wie oben erwähnt, erstellen wir jeden Tag mehrere neue Modelle, geben die Modellausgabe aus und lassen die Genauigkeit von der Unternehmensseite mit hoher Geschwindigkeit überprüfen. Zu diesem Zeitpunkt ist eine intuitive Analyse schwierig, wenn die Ausgabe in Tabellenform vorliegt, und die Kommunikation, um nur die Werte in diesem Bereich anzuzeigen, kann über mehrere Roundtrips erfolgen.
Die folgenden Maßnahmen werden ergriffen, um die oben genannten Probleme zu lösen.
Die Logik (einschließlich hoher Parameter) und Tickets zum Ändern von Trainingsdaten werden von Github-Problemen verwaltet, und die Verzweigung wird für jedes Problem abgeschnitten.
Wenn die nächste Version, die veröffentlicht werden soll, Version 1.1.0 ist und die entsprechenden Ausgabenummern 4 und 6 sind, lautet der Zweigstellenname "dev / v1.1.0 / issue4_6". Zum Zeitpunkt der Veröffentlichung wird es einmal in v1.1.0
branch zusammengeführt und die Tag-Verwaltung wird ebenfalls durchgeführt.
Alle zum Lernen und Schätzen verwendeten Dateien werden von s3 verwaltet.
In s3 wird ein Bucket für maschinelles Lernen vorbereitet, und Zwischendateien werden unter derselben Verzeichnisstruktur (dev / v1.1.0 / issue4_6
) wie der Zweigstellenname gespeichert.
Wenn Sie gefragt werden, warum der geschätzte Wert hier ist, können Sie die Ursache mithilfe von SHAP ermitteln. Fügen Sie daher beim Schätzen die Spalte shape_value hinzu. Es ist. Es gibt verschiedene Artikel über SHAP, bitte lesen Sie sie.
Erklärung der Interpretation des maschinellen Lernmodells mit Shap
Einfach ausgedrückt, sagt es uns, "wie viel jedes Merkmal zum geschätzten Wert beigetragen hat".
import shap
def calc_shap(df_, feature_list, model, rank_th=5) -> pd.core.frame.DataFrame:
'''shap_Fügen Sie eine Wertespalte hinzu
Args:
df_ (pd.core.frame.DataFrame):Daten, für die Sie die geschätzte Miete nach dem Hinzufügen des Funktionsbetrags berechnen möchten
feature_list ([str]):Liste der Funktionsnamen
model :Lernmodell
rank_th (int): shap_Wie viele Funktionen mit hohem Wert sollten angezeigt werden? Standard 5.
Returns:
pd.core.frame.DataFrame.
'''
df = df_.copy()
explainer = shap.TreeExplainer(model)
shap_values = explainer.shap_values(df[feature_list])
shap_df = pd.DataFrame(shap_values, columns=feature_list) # df[feature_values]Datenrahmen, in dem alle Werte von
shap_rank = shap_df.applymap(lambda x: abs(x)).rank(axis=1, ascending=False, method='min') #Für jeden Datensatz,Die mit einem großen absoluten Wert(⇔ Hoher Beitrag)Ranking von
main_contri_col = {i: [col for col in r.keys() if r[col] <= rank_th] for i, r in shap_rank.iterrows()} #Beitragsrang für jeden Datensatz_Spaltenliste bis th abrufen
main_contri_val = [shap_df.loc[i, main_contri_col[i]].to_dict() for i in main_contri_col.keys()] #Beitragsrang für jeden Datensatz_Holen Sie sich Spalten bis th und ihren Beitrag
df['shap_value'] = main_contri_val
return df
Der Wert in dieser Formformspalte ist eine JSON-Zeichenfolge "{" Area ": 22627," Age ": 717," hoge1 ": -5409," hoge2 ": 2968," hoge3 ": 3791}" Es sieht aus wie das. Dies ist nützlich, da Sie feststellen können, dass der Bereich einen wahnsinnigen Beitrag leistet, und wenn Sie ihn nachschlagen, können Sie feststellen, dass die Bereichsreihenfolge des geschätzten Datensatzes falsch war.
Damit Mitglieder der Geschäftsseite die Genauigkeit unabhängig und mit hoher Geschwindigkeit überprüfen können Nicht nur die einfache Genauigkeit und der Unterschied zwischen dem Ergebnis und der vorherigen Logik, sondern auch die Lerndaten und der geschätzte Wert für verschiedene Eigenschaften werden visualisiert. Die folgenden Bilder sind vergangene Beispiele, aber die Eigenschaften mit hohen Schätzungen sind in Orange und die Eigenschaften mit niedrigen Schätzungen in Hellblau dargestellt. (Normalerweise werden Trainingsdaten auch mit schwarzen Kreisen dargestellt.)
Der Visualisierungscode ist unten.
'''Visualisierung der geschätzten Miete durch Folium
Required:
pandas
folium
matplotlib
'''
import subprocess
import pandas as pd
import folium
import matplotlib.colors as cl
def calc_RGB_value(norm_rent: float) -> str:
'''0-Gibt eine auf 1 Skala komprimierte Zahl als hexadezimale RGB-Notation zurück
Die billigste Immobilie ist hellblau,Machen Sie teure Eigenschaften orange
Args:
norm_rent (float): 0-Zahlenwert auf 1 Skala komprimiert
Returns:
str
ex: #54b0c5
'''
R_val = 41 + (255 - 41) * norm_rent
G_val = 182 + (150 - 182) * norm_rent
B_val = 246 + (0 - 246) * norm_rent
return cl.to_hex((R_val / 255, G_val / 255, B_val / 255, 1))
def add_color_col(df_: pd.core.frame.DataFrame) -> pd.core.frame.DataFrame:
'''Farbspalte hinzufügen
Args:
df_ (pd.core.frame.DataFrame): estimated_Datenrahmen mit Mietspalte
Returns:
pd.core.frame.DataFrame
'color'Spalte hinzufügen und zurückgeben
'''
df = df_.copy()
norm = cl.Normalize(vmin=df['estimated_rent'].min(), vmax=df['estimated_rent'].max())
norm_rent_ = [norm(v) for v in df['estimated_rent']] #Geschätzte Miete 0,Machen Sie es 1 Skala
color_ = [calc_RGB_value(norm_rent) for norm_rent in norm_rent_]
df["color"] = color_
return df
class Drawer:
def __init__(self, ld_path, ed_path):
self.read_ld(ld_path)
self.read_ed(ed_path)
self.add_color_col()
self.init_map()
def read_ld(self, ld_path):
'''Trainingsdaten lesen
'''
self.ld = pd.read_csv(ld_path)
assert 'answer_rent' in self.ld.columns
def read_ed(self, ed_path):
'''Datenlesung nach geschätzter Mietberechnung
'''
self.ed = pd.read_csv(ed_path)
assert 'estimated_rent' in self.ld.columns
def add_color_col(self):
self.ed = add_color_col(self.ed)
self.ld['color'] = '#262626' #schwarz
def init_map(self):
'''Karte initialisieren
'''
self.map = folium.Map(
location=[self.ed.latitude.mean(),self.ed.longitude.mean()],
zoom_start=6, tiles='cartodbpositron')
def add_ld_plot(self, size=15):
'''Trainingsdatenplot
size (int):Die Größe des Plotkreises. Standard 15.
'''
for i, row in self.ld.iterrows():
folium.Circle(
radius=size, location=[row['latitude'], row['longitude']],
popup='Name des Anwesens: %s' % (row['Name des Anwesens'] if 'Name des Anwesens' in row.keys() else '' +
'<br/>Richtige Miete: {:,.0f}Kreis/Tsubo'.format(row['ans_rent']),
color=row['color'], fill_color=row['color']).add_to(self.map)
def add_ed_plot(self, size=5):
'''Geschätzte Miete Grundstück
size (int):Die Größe des Plotkreises. Standard 5.
'''
for i, row in self.ld.iterrows():
folium.Circle(
radius=size, location=[row['latitude'], row['longitude']],
popup='Name des Anwesens: %s' % (row['Name des Anwesens'] if 'Name des Anwesens' in row.keys() else '' +
'<br/>Geschätzte Miete: {:,.0f}Kreis/Tsubo'.format(row['estimated_rent']),
color=row['color'], fill_color=row['color']).add_to(self.map)
if __name__ == '__main__':
drawer = Drawer(
ld_path='s3://hogehoge/dev/v1.1.0/issue4_6/ld.csv',
ed_path='s3://hogehoge/dev/v1.1.0/issue4_6/ed.csv')
drawer.add_ld_plot()
drawer.add_ed_plot()
drawer.map.save('map.html')
subprocess.call(
['aws', 's3', 'mv', 'map.html', 's3://hogehoge/dev/v1.1.0/issue4_6/map.html'])
Obwohl die Methode noch primitiv ist, wird die Verwaltung der Datencode-Versionssynchronisation durch die obige Methode durchgeführt. In Zukunft denke ich darüber nach, MLflow einzuführen, um die Verwaltung zu vereinfachen, aber ich werde eine Fortsetzung schreiben, sobald es eingeführt wird.
Bei estie sind wir immer auf der Suche nach Ingenieuren, die von neuen Technologien und Full-Stack-Ingenieuren begeistert sind! https://www.wantedly.com/companies/company_6314859/projects
estie -> https://www.estie.jp estiepro -> https://pro.estie.jp Unternehmensseite-> https://www.estie.co.jp
Recommended Posts