Das Zurückgeben einer Liste von apply
ist eine gefährliche Operation, da nicht garantiert wird, dass das resultierende Objekt entweder eine Serie oder ein DataFrame ist. In bestimmten Fällen können Ausnahmen auftreten. Lassen Sie uns ein einfaches Beispiel durchgehen:
df = pd.DataFrame(data=np.random.randint(0, 5, (5,3)),
columns=['a', 'b', 'c'])
df
a b c
0 4 0 0
1 2 0 1
2 2 2 2
3 1 2 2
4 3 0 0
Es gibt drei mögliche Ergebnisse bei der Rückgabe einer Liste von apply
1) Wenn die Länge der zurückgegebenen Liste nicht der Anzahl der Spalten entspricht, wird eine Reihe von Listen zurückgegeben.
df.apply(lambda x: list(range(2)), axis=1) # returns a Series
0 [0, 1]
1 [0, 1]
2 [0, 1]
3 [0, 1]
4 [0, 1]
dtype: object
2) Wenn die Länge der zurückgegebenen Liste gleich der Anzahl der Spalten ist, wird ein DataFrame zurückgegeben und jede Spalte erhält den entsprechenden Wert in der Liste.
df.apply(lambda x: list(range(3)), axis=1) # returns a DataFrame
a b c
0 0 1 2
1 0 1 2
2 0 1 2
3 0 1 2
4 0 1 2
3) Wenn die Länge der zurückgegebenen Liste der Anzahl der Spalten für die erste Zeile entspricht, jedoch mindestens eine Zeile enthält, in der die Liste eine andere Anzahl von Elementen als die Anzahl der Spalten enthält, wird ein ValueError ausgelöst.
i = 0
def f(x):
global i
if i == 0:
i += 1
return list(range(3))
return list(range(4))
df.apply(f, axis=1)
ValueError: Shape of passed values is (5, 4), indices imply (5, 3)
Beantwortung des Problems ohne Anwendung
Die Verwendung apply
mit Achse = 1 ist sehr langsam. Mit grundlegenden iterativen Methoden ist es möglich, eine viel bessere Leistung (insbesondere bei größeren Datenmengen) zu erzielen.
Erstellen Sie einen größeren Datenrahmen
df1 = df.sample(100000, replace=True).reset_index(drop=True)
Timings
# apply is slow with axis=1
%timeit df1.apply(lambda x: mylist[x['col_1']: x['col_2']+1], axis=1)
2.59 s ± 76.8 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
# zip - similar to @Thomas
%timeit [mylist[v1:v2+1] for v1, v2 in zip(df1.col_1, df1.col_2)]
29.5 ms ± 534 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
@ Thomas Antwort
%timeit list(map(get_sublist, df1['col_1'],df1['col_2']))
34 ms ± 459 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)