Première édition: 2020/3/10
Auteur: Soichi Takashige, Masahiro Ito, Hitachi, Ltd.
Dans cet article, nous présenterons le savoir-faire en matière de conception du prétraitement des données et les résultats de la vérification des performances du prétraitement des données lors de la conception d'un système intégrant un modèle d'apprentissage automatique.
Dans le deuxième volet, nous présenterons le savoir-faire en matière d'amélioration des performances et les résultats de vérification dans le prétraitement des données à l'aide de Python.
** Liste des messages: **
Avant de présenter le savoir-faire de conception et les résultats de la vérification des performances, nous présenterons les référentiels appelés références dans la vérification. Cette fois, j'ai utilisé BigBench, qui est l'un des programmes de référence pour l'analyse de Big Data. BigBench est un programme de référence qui simule un système qui analyse des données telles que l'accès des utilisateurs sur des sites de commerce électronique en ligne, et cible des données structurées ou semi-structurées telles que des données sur RDB et des journaux Web. Des scénarios d'entreprise individuels et des programmes de référence sont définis. La figure 1 montre la structure des données BigBench.
Figure 1 Structure des données BigBench
Cette fois, parmi les 30 scénarios commerciaux de BigBench, nous nous sommes référés au scénario commercial n ° 5, qui est le traitement le plus compliqué et peut être considéré comme un exemple typique de prétraitement de données, en tant que cible de vérification, et implémenté le code initial de manière indépendante en python. .. Le scénario commercial n ° 5 ressemble à ceci:
Créez un modèle de régression logistique qui estime les catégories de produits qui intéressent l'utilisateur à partir de l'historique d'accès Web de l'utilisateur de la boutique en ligne.
La figure 2 présente un aperçu du traitement du scénario commercial n ° 5.
Figure 2 Aperçu du traitement du scénario d'affaires BigBench n ° 5
Ce scénario est divisé en une phase d'apprentissage et une phase d'inférence. Dans la phase d'apprentissage, des informations connexes telles que l'historique d'accès (web_clickstreams) aux magasins en ligne sur le Web, la base de données d'informations sur les produits (article), la base de données d'informations sur les utilisateurs (clients) (client, démographie_client), etc. Organisez l'historique de transition de la boutique en ligne et les caractéristiques des utilisateurs (éducation, sexe, etc.) sous forme de données statistiques. Sur la base de ces données statistiques, nous créons un modèle de régression qui estime si un utilisateur est intéressé par un domaine particulier (par exemple, «Livres»). Dans la phase d'inférence, des données statistiques qui agrègent l'historique d'accès etc. pour un utilisateur sont créées et appliquées au modèle de régression créé dans la phase d'apprentissage pour estimer l'intérêt de l'utilisateur dans le champ "Livres". Je vais. Ici, la figure 3 montre le flux de prétraitement des données mis en œuvre pour cette vérification en se référant à l'intérieur du scénario commercial n ° 5.
Figure 3 Aperçu de l'algorithme de prétraitement pour le scénario commercial BigBench n ° 5 (phase d'apprentissage)
Ce prétraitement comprend les quatre phases suivantes.
** 1) [Combinaison de l'historique d'accès et des informations sur le produit] ** Associez l'historique d'accès Web à la base de données du produit afin qu'il puisse être classé par catégorie ((1) sur la figure 3).
** 2) [Agréger par utilisateur] ** Le nombre de clics sur un produit de chaque catégorie est affiché dans le tableau pour chaque utilisateur accédant (②③ sur la Fig. 3).
** 3) [Combinaison des informations utilisateur] ** En associant les informations d'attribut de l'utilisateur accédant aux informations agrégées pour chaque utilisateur, il est possible de classer par l'attribut de l'utilisateur (④⑤ sur la figure 3).
** 4) [Caractéristiques] ** Convertissez les informations textuelles, etc. en une chaîne numérique afin qu'elles puissent être utilisées dans l'apprentissage automatique (⑥ et ⑦ sur la figure 3).
La figure 4 montre un exemple d'implémentation du prétraitement des données dans Python pour le scénario commercial BigBench n ° 5. Cette fois, sur la base de ce code, nous envisagerons d'améliorer le traitement.
Code initial(Pour PoC)
import pandas as pd
import numpy as np
#Lecture des données
web_clickstreams = pd.read_csv("web_clickstreams.csv")
item = pd.read_csv("item.csv");
customer = pd.read_csv("customer.csv")
customer_demographics = pd.read_csv("customer_demographics.csv")
#Processus (1): Combinaison de l'historique d'accès et des informations produit
data = web_clickstreams.loc[web_clickstreams['web_clickstreams.wcs_user_sk'].notnull(), :]
data = pd.merge(data, item, how='inner', left_on=['wcs_item_sk'], right_on=['i_item_sk'])
#Processus (2): diviser les données par ID utilisateur
data = data.groupby('wcs_user_sk')
#Processus ③: agréger par utilisateur
i_category_index = "Books"
types = ['wcs_user_sk', 'clicks_in_category']+['clicks_in_%d'%i for i in range(1, 8)]
def summarize_per_user(data_mr):
wcs_user_sk_index = data_mr.name
# ③-1,③-2 Une catégorie de produit spécifiée(Books)Agréger le nombre d'accès à
clicks_in_category = len(data_mr[data_mr['i_category'] == i_category_index])
# ③-3 ‘i_category_id’==Calculer pour 1… 7 respectivement
# ③-3-1, ③-3-2 ‘i_category_id’==Agréger le nombre de journaux d'accès i
return pd.Series([wcs_user_sk_index, i_category_index] + \
[len(data_mr[data_mr['i_category_id']==i]) for i in range(1, 8)], \
index = types)
data = data.apply(summarize_per_user)
#Processus ④: combiner avec les informations utilisateur
data = pd.merge(data, customer, how='inner', left_on=['wcs_user_sk'], right_on=['c_customer_sk'])
#Processus ⑤: combiner avec les informations d'attribut utilisateur
data = pd.merge(data, customer_demographics, how='inner', \
left_on=['c_current_cdemo_sk'], right_on=['cd_demo_sk'])
#Processus ⑥: quantification des fonctionnalités
data['college_education'] = data['cd_education_status'].apply( \
lambda x: 1 if x == 'Advanced Degree' or x == 'College' or \
x == '4 yr Degree' or x == '2 yr Degree' else 0)
data['male'] = data['cd_gender'].apply(lambda x: 1 if x == 'M' else 0)
#Traitement ⑦:Extraire les informations nécessaires et les remplacer
result = pd.DataFrame(data[['clicks_in_category', 'college_education', 'male', \
'clicks_in_1', 'clicks_in_2', 'clicks_in_3', \
'clicks_in_4', 'clicks_in_5', 'clicks_in_6', 'clicks_in_7']])
#Enregistrer les résultats
result.to_csv('result-apply.csv')
Figure 4 Exemple de code du scénario commercial BigBench # 5
Commençons par les améliorations qui peuvent être apportées au sein de python pur. Dans le codage Python, l'optimisation logique est importante en tant que savoir-faire pour améliorer les performances. Les deux points suivants ont été examinés et appliqués en tant qu'optimisation logique qui devrait avoir un effet important sur le code de l'entreprise cible cette fois-ci.
Lorsqu'un traitement itératif est exécuté dans une boucle for, etc., le traitement n'est exécuté que sur un seul processeur en raison des restrictions Python. En réécrivant ceci dans des fonctions pandas telles que apply et map, il peut être exécuté en parallèle avec plusieurs threads en interne et accéléré.
Lors du traitement de la même plage de données dans différents cas, le filtrage des données tel qu'un filtre peut être exécuté plusieurs fois avec différentes expressions conditionnelles. Un tel code effectuera plusieurs comparaisons conditionnelles des données pour la même plage de données, ce qui se traduira par une efficacité d'exécution médiocre. Un tel traitement peut être accéléré en le réécrivant afin qu'il puisse être effectué en une seule boucle.
Cet exemple utilise la fonction pandas au moment du code de la figure 4.
Dans le code avant optimisation de la partie supérieure de la figure 5 ci-dessous, "Boucle de carte ③-3 (répétition de 0… 7)" sur la figure 3 est écrit. En regardant cela, nous nous référons à la colonne «i_category_id» des éléments du tableau appelé data_mr, et comptons le nombre d'éléments dont les valeurs sont de 1 à 7, respectivement. Dans cette implémentation, la même plage de données est recherchée 7 fois plus d'une fois. En réécrivant ce processus à l'aide de groupby, le nombre de recherches peut être réduit à un.
```python:Avant amélioration
#[Avant l'optimisation] Effectuez 7 fois toutes les recherches d'éléments
return pd.Series([wcs_user_sk_index, i_category_index] + \
[len(data_mr[data_mr['i_category_id']==i]) for i in range(1, 8)],\
index=types)
```
```python:Après amélioration
#[Après optimisation] Effectuez la recherche de tous les éléments une seule fois
clicks_in = [0] * 8
for name, df in data_mr.groupby('i_category_id'):
if name < len(clicks_in):
clicks_in[name] = len(df)
return pd.Series([wcs_user_sk_index, i_category_index] + clicks_in[1:], \
index = types);
```
Figure 5 Exemple de remplacement du processus de recherche dans une boucle par une seule recherche
Ici, mesurons en fait les performances de l'effet de l'optimisation logique illustrée à la figure 5.
Dans cette vérification des performances, AWS est utilisé et ses spécifications sont présentées dans le tableau 1 ci-dessous.
Tableau 1 Spécifications matérielles de l'environnement de vérification
Environnement de vérification du prétraitement des données Python | |
---|---|
exemple | AWS EC2 |
OS | CentOS 7 64bit |
CPU(Nombres de coeurs) | 32 |
Memory(GB) | 256 |
HDD(TB) | 5 (disque dur de 1 To x 5) |
Les versions de logiciel utilisées pour la vérification sont présentées dans le tableau 2 ci-dessous.
Tableau 2 Version du logiciel de l'environnement de vérification
Logiciel | version |
---|---|
Python | 3.7.3 |
Pandas | 0.24.2 |
Numpy | 1.16.4 |
Cette fois, nous avons mesuré les performances à l'aide des deux méthodes de traitement suivantes.
Traitement à nœud unique par Python (sans optimisation logique dans la figure 5)
Exécutez le code de la figure 4 sur Python.
Traitement à nœud unique par Python (avec optimisation logique sur la figure 5)
Exécutez le code de la figure 4 avec l'optimisation de la figure 5 sur Python.
Lors de la mesure, le temps total requis pour les trois processus suivants est mesuré.
Pour traiter les données, lisez toutes les données des tables (web_clickstream, article, client, données démographiques client) nécessaires au traitement du disque à la trame de données. Les données à lire sont un fichier texte et seront lues à partir du disque local.
Prétraitement tel que combinaison et agrégation de données pour les données lues
Ecrivez le résultat du traitement dans la banque de données
Écrivez des données au format texte sur votre disque local.
En supposant que la taille des données traitées par le système de production est d'environ 50 Go (taille estimée lorsqu'elle est étendue sur la mémoire), mesurez avec certaines tailles de données entre 1/100 de cette taille de données et la taille de production attendue Et j'ai vérifié comment le temps de traitement change. Pour chaque taille de mesure, le tableau 3 montre la taille lorsque les données d'entrée à traiter sont étendues sur la mémoire et la taille des données lorsqu'elles sont initialement enregistrées sur le disque dur au format texte. Désormais, la taille des données dans le résultat de la mesure utilise la valeur de la taille des données dans la mémoire.
Tableau 3 Taille des données de mesure
Pourcentage de la taille des données de production[%] | 1 | 5 | 10 | 25 | 50 | 75 | 100 | 200 | 300 |
---|---|---|---|---|---|---|---|---|---|
Nombre de lignes de données- web_clickstreams | 6.7M | 39M | 83M | 226M | 481M | 749M | 1.09G | 2.18G | 3.39G |
Nombre de lignes de données- item | 18K | 40K | 56K | 89K | 126K | 154K | 178K | 252K | 309K |
Nombre de lignes de données- customer | 99K | 221K | 313K | 495K | 700K | 857K | 990K | 1.4M | 1,715 |
Nombre de lignes de données- customer_demographics | 1.9M | 1.9M | 1.9M | 1.9M | 1.9M | 1.9M | 1.9M | 1.9M | 1.9M |
Taille des données en mémoire(GB) | 0.4 | 1.9 | 3.9 | 10.3 | 21.8 | 33.7 | 49.1 | 97.9 | 152.1 |
Taille des données sur le disque dur(GB) | 0.2 | 1.0 | 2.2 | 6.3 | 13.8 | 21.7 | 29.8 | 63.6 | 100.6 |
La figure 6 montre les résultats de la mesure du temps de traitement en exécutant chacun des deux types de traitement (avec / sans optimisation logique sur la figure 5) pour chaque taille de données pour le scénario commercial n ° 5 de BigBench. .. De plus, la taille des données atteignait environ 22 Go (50% de la taille des données de production), et lorsque j'ai essayé de traiter des données de plus grande taille, elles ne pouvaient pas être traitées en raison d'une mémoire insuffisante. Ici, lorsque la taille des données d'entrée est de 0,4 Go (le point le plus à gauche dans le graphique de la figure 6), le temps d'exécution est de 412 secondes sans optimisation logique et de 246 secondes avec l'optimisation logique, ce qui est d'environ 40%. Il a été raccourci. De plus, lorsque la taille des données d'entrée est de 22 Go (le point le plus à droite du graphique de la figure 6), le temps d'exécution est de 5039 secondes sans optimisation logique et de 3892 secondes avec l'optimisation logique, ce qui représente une réduction d'environ 23%. Je suis resté à.
Figure 6 Résultats de la mesure du temps de prétraitement des données pour chaque taille de données d'entrée
La figure 7 montre la progression de l'utilisation du processeur, de la mémoire et des E / S disque lors du traitement de données de taille 22 Go. Cette fois, la machine de vérification a 32 cœurs, mais Python ne peut utiliser qu'un seul cœur. Par conséquent, le taux d'utilisation du processeur est toujours d'environ 1/32 = 3%. D'autre part, vous pouvez voir qu'environ 200 Go de mémoire sont consommés pour le traitement des données d'entrée d'une taille d'environ 22 Go sur la mémoire. Ceci est probablement dû au fait que le résultat du traitement intermédiaire est conservé dans la mémoire pendant le traitement des données, de sorte que sa taille est également consommée. Il peut être confirmé que les E / S sont effectuées uniquement au moment de la lecture initiale des données et que les E / S ne se produisent pas pendant le traitement des données et sont essentiellement traitées en mémoire.
Figure 7 Changements temporels dans l'utilisation du processeur, de la mémoire et des E / S dans l'environnement Python + Pandas
Il a été confirmé qu'un effet d'amélioration des performances de 40 à 23% peut être obtenu par une optimisation logique qui évite de rechercher les mêmes données à plusieurs reprises. À ce stade, l'effet d'amélioration des performances diminue à mesure que la taille des données augmente, mais cela est dû au fait que l'effet d'amélioration dépend des caractéristiques des données (plage de valeurs et distribution) et que les caractéristiques changent lorsque la taille des données augmente. Je pense que c'était à cause de ça. Par conséquent, une suroptimisation de la logique avec des données de taille différente (sous-ensemble de petite taille) comme PoC peut avoir des effets différents sur les données à l'échelle de la production. Par conséquent, il est recommandé d'effectuer une optimisation logique lors du réglage final.
Dans cet article, nous avons présenté le savoir-faire d'amélioration des performances du prétraitement des données numériques à l'aide de Python et les résultats de la vérification des performances sur la machine réelle. La prochaine fois, je présenterai les résultats de la vérification des performances lorsque Spark, qui est une plate-forme de traitement distribuée parallèle, est utilisée pour le prétraitement des données numériques.
Recommended Posts