से एक सूची वापस apply
करना एक खतरनाक ऑपरेशन है क्योंकि परिणामी वस्तु को श्रृंखला या डेटाफ़्रेम होने की गारंटी नहीं है। और अपवाद कुछ मामलों में उठाए जा सकते हैं। चलो एक सरल उदाहरण के माध्यम से चलते हैं:
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
सूची से लौटने के साथ तीन संभावित परिणाम हैं apply
1) यदि लौटी हुई सूची की लंबाई स्तंभों की संख्या के बराबर नहीं है, तो सूचियों की एक श्रृंखला वापस आ जाती है।
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) जब लौटी सूची की लंबाई स्तंभों की संख्या के बराबर होती है तो एक DataFrame वापस कर दिया जाता है और प्रत्येक कॉलम को सूची में संबंधित मान मिलता है।
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) यदि दी गई सूची की लंबाई पहली पंक्ति के लिए स्तंभों की संख्या के बराबर है, लेकिन कम से कम एक पंक्ति है जहां सूची में स्तंभों की संख्या की तुलना में तत्वों की एक अलग संख्या है, तो एक ValueError उठाया जाता है।
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)
बिना आवेदन के समस्या का जवाब देना
apply
अक्ष = 1 के साथ उपयोग करना बहुत धीमा है। बुनियादी पुनरावृत्ति विधियों के साथ बहुत बेहतर प्रदर्शन (विशेष रूप से बड़े डेटासेट पर) प्राप्त करना संभव है।
बड़ा डेटाफ़्रेम बनाएँ
df1 = df.sample(100000, replace=True).reset_index(drop=True)
समय
# 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)
@ थोमस का जवाब
%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)