[PYTHON] Pourquoi utiliser Pandas Apply ()

TL;DR

Je vais résumer l'histoire de l'utilisation de apply () lors du prétraitement des données avec Pandas.

Qu'est-ce que les pandas

http://pandas.pydata.org/pandas-docs/stable/ pandas est une bibliothèque qui fournit les méthodes nécessaires à l'analyse des données en Python. Il peut gérer un large éventail de données, des séries chronologiques aux séries de données telles que les tableaux, et peut être agrégé à grande vitesse. Dans le monde d'aujourd'hui, vous entendez souvent le cas de "l'analyse des données avec Python".

Travail d'analyse de données dans l'entreprise

Lors de l'exécution de travaux d'analyse de données dans Moff, nous traitons souvent les données après avoir extrait les données préliminaires, puis les analyser sur place. Après avoir dessiné la table de données que vous souhaitez créer à la fin, vous devrez exécuter un pré-traitement d'ici là.

Ce qui a été fait en tant que débutant.

Par exemple, supposons que vous ayez le jeu de données suivant.

スクリーンショット 2019-12-24 11.04.27.png

Après cela, supposons que vous souhaitiez prétraiter "Je veux ajouter un nouveau nombre de caractères dans le nom à la colonne".

À cette époque, il était particulièrement observé chez les stagiaires qui commençaient tout juste la programmation, mais le code de prétraitement suivant était souvent vu dans le prétraitement.

data['len'] = 0
for k, d in data['name'].iteritems():
    data['len'][k] = len(d)

Certes, cela suffit pour le résultat de sortie, et je pense que quelques lignes de données prendront certainement autant de temps.

Essayez de le gérer avec apply ().

Maintenant, traitons-le avec apply (). apply () est l'une des méthodes fournies dans les types DataFrame et Series. Dans les expressions DataFrame et Series, chaque valeur du DataFrame groupé est utilisée comme argument et la valeur de retour de la fonction donnée à l'argument de apply () est utilisée. Il peut renvoyer des valeurs Series, DataFrame ou scalaires.

https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.apply.html https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Series.apply.html

Dans l'exemple précédent, si vous créez une fonction qui renvoie len, elle ressemblera à ceci.

def return_len(x)
    return len(x)

data['len'] = data['name'].apply(return_len)

Si vous connaissez l'expression lambda (fonction anonyme), vous pouvez également effectuer les opérations suivantes.

data['len'] = data['name'].apply(lambda x: len(x))

Je pense que ce sera relativement simple en termes de description.

Comme vous l'avez peut-être remarqué, cette fois j'ai introduit une fonction qui renvoie le résultat de len () en implémentant la fonction. Si vous y réfléchissez bien, len () lui-même est aussi une fonction, vous pouvez donc le faire comme ceci.

data['len'] = data['name'].apply(len)

S'il s'agit d'un processus simple, il peut être possible de le résoudre avec une boucle for, mais lorsque vous envisagez un prétraitement plus compliqué, il est préférable d'en faire une fonction et de l'appliquer avec apply () plutôt que ce qui précède, et de remarquer les erreurs, etc. Je pense que ce sera moins cher.

Quelle est la vitesse de traitement

Dans l'exemple ci-dessus, étant donné que la quantité de données est petite, je pense qu'il y a une différence dans la vitesse de traitement, je vais donc montrer le résultat de l'application du traitement qui génère la longueur des données de chaîne de caractères aléatoires. L'environnement de vérification est le suivant.

# of data for loop pandas.DataFrame.apply()
100 3.907sec 0.079sec
10000 415.032sec 0.231sec
100000 3100.906sec 1.283sec

Comme vous pouvez le voir, même avec environ 100 cas, il y a une différence d'environ 3,8 secondes, et lorsque le nombre de cas est de 10 000 ou 100 000, la différence de temps nécessaire pour produire le résultat devient énorme. Il est clair qu'il est préférable d'utiliser apply () pour obtenir un résultat rapide, quelle que soit la taille de l'ensemble de données ou le prétraitement.

Que fait Apply ()? Quelle est la substance?

Par exemple, voici le corps principal de Apply of DataFrame https://github.com/pandas-dev/pandas/blob/5a7b5c958c6f004c395136f9438a1ed6c04861dd/pandas/core/frame.py#L6440

Si vous suivez frame_apply ()

https://github.com/pandas-dev/pandas/blob/5a7b5c958c6f004c395136f9438a1ed6c04861dd/pandas/core/apply.py#L26

Il semble que quelque chose soit écrit dans une classe appelée FrameApply.

https://github.com/pandas-dev/pandas/blob/5a7b5c958c6f004c395136f9438a1ed6c04861dd/pandas/core/apply.py#L56

Puisque nous appelons get_result () sur frame_apply (), nous allons suivre le processus.

https://github.com/pandas-dev/pandas/blob/5a7b5c958c6f004c395136f9438a1ed6c04861dd/pandas/core/apply.py#L144

Il existe une branche en fonction du paramètre, mais il semble que ce qui suit est appelé à moins qu'un argument optionnel ne soit donné.

https://github.com/pandas-dev/pandas/blob/5a7b5c958c6f004c395136f9438a1ed6c04861dd/pandas/core/apply.py#L269

Il semble que libreduction.compute_reduction () effectue le calcul dans apply_standard (). Après cela, il semble que apply_series_generator () et wrap_results () produisent des résultats. Il semble que la libreduction soit dans / _lib / reduction.pyx.

https://github.com/pandas-dev/pandas/blob/master/pandas/_libs/reduction.pyx

Apparemment, cela semble se comporter comme diviser les données de la matrice avec numpy.ndarray.shape dans Reducer, et faire diverses choses à partir de for i in range (self.n results):.

https://github.com/pandas-dev/pandas/blob/5a7b5c958c6f004c395136f9438a1ed6c04861dd/pandas/_libs/reduction.pyx#L88

De là, cela semble être une histoire sur Numpy. Même si vous parcourez le code ci-dessus, Pandas Dans ce qui précède, il semble qu'aucun point ne soit défini dans le calcul, il semble donc que le traitement soit conçu sur Numpy. Car, à la fin, il y a res = self.f (chunk) sur le réducteur ci-dessus, et le point qu'il est spécialement conçu dans le processus de calcul après le processus d'application de la fonction au ndarray de Numpy. Je n'ai pas pu le trouver. Il y avait une description selon laquelle il était traité séparément dans Chunk, mais les détails du traitement réel n'étaient pas clairs au moment de res = self.f (chunk) de l'application de la fonction, et du traitement du côté Numpy par la suite Il semble être complété par. Dans la mesure où cela est dit dans les rues, il est logique d'ajouter que le processus de calcul dans Numpy est plus rapide que le processus de calcul en Python pur seul.

J'aimerais en savoir un peu plus, mais comme il est volumineux d'écrire plus, je profiterai d'une autre occasion pour spécifier le traitement dans Numpy. Quoi qu'il en soit, il a été décidé que ce n'était pas du moins sur Pandas. (Bien qu'il ne soit toujours pas clair si cela dépend des performances du langage ou s'il est conçu par un traitement de calcul)

D'autres concernant la carte, appliquer, appliquer la carte, etc.

Sous la forme d'un dérivé de apply (), il existe respectivement map () et applymap () dans Series et DataFrame. À première vue, je me demandais ce qui était différent, alors j'ai fait une recherche rapide et j'ai trouvé que les différences étaient résumées dans la réponse StackOverFlow ci-dessous. https://stackoverflow.com/a/56300992/7649377

Si vous ne supprimez que les points principaux,

Est-ce là le point?

Résumé

La prochaine fois que j'écrirai un article avec cette histoire, je lirai Numpy et l'attraperai. Merci beaucoup.

Recommended Posts

Pourquoi utiliser Pandas Apply ()
Pourquoi utiliser Linux
Pourquoi vous devriez utiliser urlopen au lieu d'urlretrieve pour télécharger des fichiers Python
Vous devez savoir si vous utilisez Python! 10 bibliothèques utiles
Comment utiliser Pandas 2
Trois raisons pour lesquelles les apprenants en machine learning devraient utiliser Python
Raisons pour lesquelles l'évaluation de la matrice de confusion telle que la précision ne peut pas être utilisée
[Pandas speedup] Si vous pensez que la fusion est lente, utilisez la carte
Comment utiliser Pandas Rolling
Vous ne devez pas utiliser l'option --color = always de la commande grep