[PYTHON] Comparaison de vitesse lors de la recherche à l'aide de plusieurs clés dans les pandas (MultiIndex vs Others)

introduction

MultiIndex est utile pour extraire des lignes à l'aide de plusieurs clés, mais je recherchais plusieurs clés sans connaître son existence, alors comparons la vitesse d'exécution avec et sans MultiIndex. J'ai fait.

Environnement d'exécution

L'exécution du code et la mesure de la vitesse ont été effectuées sur le Jupyter Notebook. Aussi, le code ci-dessous

import pandas as pd

Est en cours d'exécution.

Préparation des données

sample.csv


city,year,number,dividion
Tokyo,2019,1,A
Tokyo,2019,2,B
Tokyo,2020,1,C
Tokyo,2020,2,D
Tokyo,2018,1,E
Tokyo,2018,2,F
Kyoto,2019,1,G
Kyoto,2019,2,H
Kyoto,2020,1,I
Kyoto,2020,2,J
Kyoto,2018,1,K
Kyoto,2018,2,L

Essayez d'importer sample.csv dans DataFrame.

df1 = pd.read_csv("sample.csv")

Ensuite, il sera lu comme ceci.

city year number dividion
0 Tokyo 2019 1 A
1 Tokyo 2019 2 B
2 Tokyo 2020 1 C
3 Tokyo 2020 2 D
4 Tokyo 2018 1 E
5 Tokyo 2018 2 F
6 Kyoto 2019 1 G
7 Kyoto 2019 2 H
8 Kyoto 2020 1 I
9 Kyoto 2020 2 J
10 Kyoto 2018 1 K
11 Kyoto 2018 2 L
Dans ce tableau, la division est définie de manière unique par trois clés: ville, année et nombre. # Méthode 1: Spécifiez plusieurs conditions sans rien concevoir ## Vitesse de traitement, y compris la lecture csv
%%timeit
df1 = pd.read_csv("sample.csv")
df1[(df1["city"] == "Tokyo")&(df1["year"] == 2019)&(df1["number"] == 1)].iloc[0]

Résultat de l’exécution </ b> 2.65 ms ± 48.9 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

Si csv a été lu à l'avance

%timeit df1[(df1["city"] == "Tokyo")&(df1["year"] == 2019)&(df1["number"] == 1)].iloc[0]

Résultat de l’exécution </ b> 1.44 ms ± 101 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
La méthode 1 nécessitait un temps d'exécution considérable lors du traitement d'une grande quantité de données, la méthode 2 a donc été utilisée pour le traitement.

Méthode 2: Ajouter et rechercher des colonnes de clés composées

Créez un élément unique en ajoutant les trois éléments de la ville, de l'année et du nombre sous forme de chaîne de caractères.

df2 = pd.read_csv("sample.csv")
# city, year,Extraire la colonne numérique sous forme de liste (les éléments sont convertis en str)
cities = list(map(str, df2["city"].values.tolist()))
years = list(map(str, df2["year"].values.tolist()))
numbers = list(map(str, df2["number"].values.tolist()))
#Ajoutez trois chaînes ensemble pour générer une clé unique
keys = [city+year+number for city, year, number in zip(cities, years, numbers)]
df2["key"] = keys

Ensuite, un tel DataFrame est créé.

city year number dividion key
0 Tokyo 2019 1 A Tokyo20191
1 Tokyo 2019 2 B Tokyo20192
2 Tokyo 2020 1 C Tokyo20201
3 Tokyo 2020 2 D Tokyo20202
4 Tokyo 2018 1 E Tokyo20181
5 Tokyo 2018 2 F Tokyo20182
6 Kyoto 2019 1 G Kyoto20191
7 Kyoto 2019 2 H Kyoto20192
8 Kyoto 2020 1 I Kyoto20201
9 Kyoto 2020 2 J Kyoto20202
10 Kyoto 2018 1 K Kyoto20181
11 Kyoto 2018 2 L Kyoto20182
Ci-après, la vitesse est mesurée de la même manière que dans la méthode 1. ## Vitesse de traitement, y compris la lecture csv
df2 = pd.read_csv("sample.csv")
cities = list(map(str, df2["city"].values.tolist()))
years = list(map(str, df2["year"].values.tolist()))
numbers = list(map(str, df2["number"].values.tolist()))
keys = [city+year+number for city, year, number in zip(cities, years, numbers)]
df2["key"] = keys
df2[df2["key"] == "Tokyo20191"].iloc[0]

Résultat de l’exécution </ b> 2.5 ms ± 136 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

Lorsque csv est lu et prétraité

%timeit df2[df2["key"] == "2019Tokyo1"].iloc[0]

Résultat de l’exécution </ b> 569 µs ± 5.39 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

Vous pouvez voir que la vitesse d'exécution, y compris la lecture csv, ne change pas, mais la vitesse d'exécution de la recherche n'a augmenté que de l'ordre de la microseconde.

Lors de l'utilisation de MultiIndex

Maintenant que j'ai appris cette méthode pour la première fois, examinons laquelle est plus rapide que la méthode 2. Consultez la documentation officielle (https://pandas.pydata.org/pandas-docs/stable/user_guide/advanced.html) pour plus d'informations sur MultiIndex.

Si vous spécifiez la ville, l'année et le nombre comme index, ils seront lus comme suit.

df3 = pd.read_csv("sample.csv",index_col=["city","year","number"])
dividion
city year number
Tokyo 2019 1 A
2 B
2020 1 C
2 D
2018 1 E
2 F
Kyoto 2019 1 G
2 H
2020 1 I
2 J
2018 1 K
2 L
Effectuez une recherche et mesurez la vitesse. ## Vitesse de traitement, y compris la lecture csv
df3 = pd.read_csv("sample.csv",index_col=["city","year","number"])
df3.loc[("Tokyo",2019,1)]

Résultat de l’exécution </ b> 2.64 ms ± 148 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

Si csv a été lu à l'avance

%timeit df2[df2["key"] == "2019Tokyo1"].iloc[0]

Résultat de l’exécution </ b> 151 µs ± 12.1 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

Bien qu'il n'y ait pas de grande différence dans la vitesse d'exécution, y compris la lecture csv, le résultat est que la vitesse d'exécution lors de la lecture à l'avance est environ 3,8 fois plus rapide que la méthode 2.

Résumé

Les résultats obtenus à ce jour sont résumés dans le tableau ci-dessous.

Méthode 1 Méthode 2 Méthode 3
Y compris la lecture csv 2,65 ms 2,5 ms 2,64 ms
Recherche uniquement 1,44 ms 569 µs 151 µs La méthode 2 que j'utilisais était un peu plus rapide en termes de temps d'exécution, y compris la lecture csv, mais une fois lue, il était plus rapide d'utiliser MultiIndex. À propos, la méthode 2 rend le code plus long et les données à stocker dans le DataFrame augmentent, il semble donc préférable d'utiliser MultiIndex.

référence

À propos de MultiIndex of pandas Mesurer la vitesse du code avec jupyter