[PYTHON] Geschwindigkeitsvergleich bei der Suche mit mehreren Schlüsseln in Pandas (MultiIndex vs Others)

Einführung

MultiIndex ist nützlich, um Zeilen mit mehreren Schlüsseln zu extrahieren, aber ich habe nach mehreren Schlüsseln gesucht, ohne deren Existenz zu kennen. Vergleichen wir also die Ausführungsgeschwindigkeit mit und ohne MultiIndex. Ich tat.

Ausführungsumgebung

Die Codeausführung und Geschwindigkeitsmessung wurden auf dem Jupyter Notebook durchgeführt. Auch der Code unten

import pandas as pd

Läuft.

Datenaufbereitung

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

Versuchen Sie, sample.csv in DataFrame zu importieren.

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

Dann wird es so gelesen.

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
In dieser Tabelle wird die Unterteilung eindeutig durch drei Schlüssel definiert: Stadt, Jahr und Nummer. # Methode 1: Geben Sie mehrere Bedingungen an, ohne etwas zu entwickeln ## Verarbeitungsgeschwindigkeit einschließlich CSV-Lesen
%%timeit
df1 = pd.read_csv("sample.csv")
df1[(df1["city"] == "Tokyo")&(df1["year"] == 2019)&(df1["number"] == 1)].iloc[0]

Ausführungsergebnis </ b> 2.65 ms ± 48.9 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

Wenn csv im Voraus gelesen wurde

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

Ausführungsergebnis </ b> 1.44 ms ± 101 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
Methode 1 erforderte eine beträchtliche Ausführungszeit bei der Verarbeitung einer großen Datenmenge, weshalb Methode 2 für die Verarbeitung verwendet wurde.

Methode 2: Zusammengesetzte Schlüsselspalten hinzufügen und durchsuchen

Erstellen Sie ein eindeutiges Element, indem Sie die drei Elemente Stadt, Jahr und Zahl als Zeichenfolge hinzufügen.

df2 = pd.read_csv("sample.csv")
# city, year,Extrahieren Sie die Zahlenspalte als Liste (Elemente werden in str konvertiert)
cities = list(map(str, df2["city"].values.tolist()))
years = list(map(str, df2["year"].values.tolist()))
numbers = list(map(str, df2["number"].values.tolist()))
#Fügen Sie drei Zeichenfolgen hinzu, um einen eindeutigen Schlüssel zu generieren
keys = [city+year+number for city, year, number in zip(cities, years, numbers)]
df2["key"] = keys

Dann wird ein solcher DataFrame erstellt.

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
Nachfolgend wird die Geschwindigkeit auf die gleiche Weise wie in Verfahren 1 gemessen. ## Verarbeitungsgeschwindigkeit einschließlich CSV-Lesen
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]

Ausführungsergebnis </ b> 2.5 ms ± 136 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

Wenn csv gelesen und vorverarbeitet wird

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

Ausführungsergebnis </ b> 569 µs ± 5.39 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

Sie können sehen, dass sich die Ausführungsgeschwindigkeit einschließlich des CSV-Lesens nicht ändert, aber die Ausführungsgeschwindigkeit der Suche hat sich nur auf die Größenordnung von Mikrosekunden erhöht.

Bei Verwendung von MultiIndex

Nachdem ich diese Methode zum ersten Mal gelernt habe, wollen wir untersuchen, welche Methode schneller als Methode 2 ist. Weitere Informationen zu MultiIndex finden Sie in der offiziellen Dokumentation (https://pandas.pydata.org/pandas-docs/stable/user_guide/advanced.html).

Wenn Sie Stadt, Jahr und Nummer als Indizes angeben, wird dies wie folgt gelesen.

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
Führen Sie eine Suche durch und messen Sie die Geschwindigkeit. ## Verarbeitungsgeschwindigkeit einschließlich CSV-Lesen
df3 = pd.read_csv("sample.csv",index_col=["city","year","number"])
df3.loc[("Tokyo",2019,1)]

Ausführungsergebnis </ b> 2.64 ms ± 148 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

Wenn csv im Voraus gelesen wurde

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

Ausführungsergebnis </ b> 151 µs ± 12.1 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

Obwohl es keinen großen Unterschied in der Ausführungsgeschwindigkeit einschließlich des CSV-Lesens gibt, ist das Ergebnis, dass die Ausführungsgeschwindigkeit beim Lesen im Voraus etwa 3,8-mal schneller ist als bei Methode 2.

Zusammenfassung

Die bisherigen Ergebnisse sind in der folgenden Tabelle zusammengefasst.

Methode 1 Methode 2 Methode 3
Einschließlich CSV-Lesung 2,65 ms 2,5 ms 2,64 ms
Nur suchen 1,44 ms 569 µs 151 µs Die von mir verwendete Methode 2 war in Bezug auf die Ausführungszeit einschließlich des CSV-Lesens etwas schneller, aber nach dem Lesen war die Verwendung von MultiIndex schneller. Übrigens verlängert Methode 2 den Code und die im DataFrame zu speichernden Daten nehmen zu. Grundsätzlich scheint es also besser zu sein, MultiIndex zu verwenden.

Referenz

Über MultiIndex von Pandas Codegeschwindigkeit mit Jupiter messen