Voici Miyano (@estie_mynfire) de Estie CTO. Le premier jour, j'ai écrit un petit contenu de niche (j'ai essayé Pandas 'Sql Upsert), mais cette fois je le fais à l'estie ** "Office" À propos de "Prévisions de loyers équitables" **.
En ce qui concerne la location de bureaux, contrairement au logement, le loyer proposé n'est pas si public (seulement un tiers ou moins des propriétés sont ouvertes au public dans les 5 quartiers centraux), et le loyer contractuel n'est fondamentalement pas disponible ** Il est difficile de collecter des données de réponse correctes **. Dans de telles circonstances, lors de l'estimation du loyer immobilier, nous vérifions conjointement l'exactitude du modèle tout en intégrant le regard professionnel de l'immobilier de bureaux du côté des entreprises.
Comme il existe de nombreuses interactions avec les sites commerciaux, j'écrirai sur ce à quoi je porte une attention particulière et ce que j'ai imaginé.
Comme mentionné ci-dessus, puisque nous travaillons avec les membres du côté commercial, les problèmes suivants sont plus susceptibles de se produire que lors du développement uniquement avec des ingénieurs ML.
Avec les commentaires des ingénieurs d'affaires et l'expansion des données sources Nous apportons fréquemment des modifications logiques telles que la suppression des propriétés hors de valeur, l'ajout de quantités de caractéristiques et la modification des données d'apprentissage, et nous apportons des améliorations chaque jour pour créer des modèles plus précis. Cependant, comme mentionné ci-dessus, la précision de ces modèles ne peut pas toujours être évaluée en utilisant uniquement des indicateurs numériques (des yeux professionnels sont également nécessaires). J'avais l'intention de faire un meilleur modèle que par le passé
** "Oh, si c'était un modèle il y a deux mois, ça aurait été une bonne valeur ici, mais c'est une valeur étrange!" **
Ce qui arrive souvent. ~~ La plupart du temps, je remarque que lorsque je suis pressé, je suis ** picotement **. ~~
Dans un tel cas, si vous pouvez immédiatement revenir à l'état du modèle précédent, vous pouvez immédiatement rechercher la cause et la refléter dans les données de production à grande vitesse.
Lors de la vérification conjointe de l'exactitude, on nous demande souvent d'expliquer la cause, par exemple "La valeur estimée ici, pourquoi est-ce une telle valeur?". Dans un tel cas, si vous pouvez expliquer, "Je suis fortement influencé par cette quantité de fonctionnalités", vous pouvez poursuivre une discussion plus significative.
Comme mentionné ci-dessus, nous créons plusieurs nouveaux modèles chaque jour, produisons la sortie du modèle et demandons au côté commercial de vérifier la précision à grande vitesse. À ce moment-là, si la sortie est au format tabulaire, l'analyse intuitive est difficile, et la communication pour afficher uniquement les valeurs dans cette zone peut se produire sur plusieurs allers-retours.
Les mesures suivantes sont prises pour résoudre ce qui précède.
La logique (y compris les paramètres élevés) et les tickets de modification des données d'entraînement sont gérés par des problèmes github, et la branche est coupée pour chaque problème.
Si la prochaine version à sortir est la v1.1.0 et que les numéros de problème correspondants sont 4 et 6, le nom de la branche sera quelque chose comme dev / v1.1.0 / issue4_6
. Au moment de la publication, il est une fois fusionné dans la branche v1.1.0
et la gestion des balises est également effectuée.
Tous les fichiers utilisés pour l'apprentissage et l'estimation sont gérés par s3.
Un compartiment pour l'apprentissage automatique est préparé dans s3, et les fichiers intermédiaires sont stockés sous la même structure de répertoires (dev / v1.1.0 / issue4_6
) que le nom de la branche.
Lorsqu'on lui a demandé «Pourquoi cette valeur estimée est-elle ici?», Il est possible de comprendre la cause en utilisant SHAP, alors ajoutez la colonne shap_value lors de l'estimation. Il est. Il existe différents articles sur SHAP, veuillez donc vous y référer.
Explication de l'interprétation du modèle d'apprentissage automatique à l'aide de Shap
En termes simples, il nous indique "combien chaque fonctionnalité a contribué à la valeur estimée".
import shap
def calc_shap(df_, feature_list, model, rank_th=5) -> pd.core.frame.DataFrame:
'''shap_Ajouter une colonne de valeur
Args:
df_ (pd.core.frame.DataFrame):Données pour lesquelles vous souhaitez calculer le loyer estimé après avoir ajouté le montant de la fonctionnalité
feature_list ([str]):Liste des noms de fonctionnalités
model :Modèle d'apprentissage
rank_th (int): shap_Combien de fonctionnalités avec une valeur élevée doivent être affichées. par défaut 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]Trame de données dans laquelle toutes les valeurs de
shap_rank = shap_df.applymap(lambda x: abs(x)).rank(axis=1, ascending=False, method='min') #Pour chaque enregistrement,Ceux avec une grande valeur absolue(⇔ Haute contribution)Classement de
main_contri_col = {i: [col for col in r.keys() if r[col] <= rank_th] for i, r in shap_rank.iterrows()} #Classement de contribution pour chaque enregistrement_Obtenir la liste des colonnes jusqu'au th
main_contri_val = [shap_df.loc[i, main_contri_col[i]].to_dict() for i in main_contri_col.keys()] #Classement de contribution pour chaque enregistrement_Obtenez des colonnes jusqu'à th et leur contribution
df['shap_value'] = main_contri_val
return df
La valeur de cette colonne shap_value est une chaîne json
{'Zone': 22627, 'Âge': 717, 'hoge1': -5409, 'hoge2': 2968, 'hoge3': 3791}
Ça ressemble à ça. Ceci est utile car vous pouvez découvrir que "la zone contribue de manière insensée", et lorsque vous la recherchez, vous pouvez découvrir que l'ordre des zones de l'enregistrement estimé était incorrect.
Afin que les membres commerciaux puissent vérifier la précision indépendamment à grande vitesse Non seulement la précision simple et la différence entre le résultat et la logique précédente, mais également les données d'apprentissage et la valeur estimée pour diverses propriétés sont visualisées. Les images suivantes sont des échantillons antérieurs, mais les propriétés avec des estimations élevées sont représentées en orange, et les propriétés avec des estimations faibles sont représentées en bleu clair. (Habituellement, les données d'entraînement sont également tracées avec des cercles noirs)
Le code de visualisation est ci-dessous.
'''Visualisation du loyer estimé par 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-Renvoie un nombre compressé à l'échelle 1 en notation hexadécimale RVB
La propriété la moins chère est bleu clair,Rendre les propriétés chères orange
Args:
norm_rent (float): 0-Valeur numérique compressée à 1 échelle
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:
'''Ajouter une colonne de couleur
Args:
df_ (pd.core.frame.DataFrame): estimated_Trame de données contenant la colonne de loyer
Returns:
pd.core.frame.DataFrame
'color'Ajouter une colonne et retourner
'''
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']] #Loyer estimé 0,Faites-en une échelle
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):
'''Lecture des données d'entraînement
'''
self.ld = pd.read_csv(ld_path)
assert 'answer_rent' in self.ld.columns
def read_ed(self, ed_path):
'''Lecture des données après calcul du loyer estimé
'''
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' #noir
def init_map(self):
'''Initialiser la carte
'''
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):
'''Graphique des données d'entraînement
size (int):La taille du cercle de l'intrigue. par défaut 15.
'''
for i, row in self.ld.iterrows():
folium.Circle(
radius=size, location=[row['latitude'], row['longitude']],
popup='Nom de la propriété: %s' % (row['Nom de la propriété'] if 'Nom de la propriété' in row.keys() else '' +
'<br/>Loyer correct: {:,.0f}Cercle/Tsubo'.format(row['ans_rent']),
color=row['color'], fill_color=row['color']).add_to(self.map)
def add_ed_plot(self, size=5):
'''Terrain de loyer estimé
size (int):La taille du cercle de l'intrigue. par défaut 5.
'''
for i, row in self.ld.iterrows():
folium.Circle(
radius=size, location=[row['latitude'], row['longitude']],
popup='Nom de la propriété: %s' % (row['Nom de la propriété'] if 'Nom de la propriété' in row.keys() else '' +
'<br/>Loyer estimé: {:,.0f}Cercle/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'])
Bien que la méthode soit encore primitive, la gestion de la synchronisation de la version du code de données est effectuée par la méthode ci-dessus. Dans le futur, je pense introduire MLflow pour le rendre plus facile à gérer, mais j'écrirai une suite dès son introduction.
Chez estie, nous sommes toujours à la recherche d'ingénieurs passionnés par les nouvelles technologies et d'ingénieurs full-stack! https://www.wantedly.com/companies/company_6314859/projects
estie -> https://www.estie.jp estiepro -> https://pro.estie.jp Site de la société-> https://www.estie.co.jp
Recommended Posts