পান্ডাস ইটারে পারফরম্যান্সের সমস্যা আছে?


96

পান্ডা থেকে আইট্রো ব্যবহার করার সময় আমি খুব খারাপ পারফরম্যান্স লক্ষ্য করেছি।

এটি কি এমন কিছু যা অন্যরা অভিজ্ঞ হয়? এটি কি ইরোরোর সাথে নির্দিষ্ট এবং কোনও নির্দিষ্ট আকারের ডেটার জন্য এই ফাংশনটি এড়ানো উচিত (আমি ২-৩ মিলিয়ন সারি নিয়ে কাজ করছি)?

গিটহাবের এই আলোচনাটি আমাকে বিশ্বাস করতে পরিচালিত করেছিল যে ডেটাফ্রেমে ডাইপিকে মিশ্রিত করার সময় এটি ঘটেছিল, তবে নীচের সরল উদাহরণটি দেখায় যে এটি একটি ডিজাইপ (ফ্লোট 64) ব্যবহার করার পরেও সেখানে রয়েছে। এটি আমার মেশিনে 36 সেকেন্ড সময় নেয়:

import pandas as pd
import numpy as np
import time

s1 = np.random.randn(2000000)
s2 = np.random.randn(2000000)
dfa = pd.DataFrame({'s1': s1, 's2': s2})

start = time.time()
i=0
for rowindex, row in dfa.iterrows():
    i+=1
end = time.time()
print end - start

কেন ভেক্টরাইজড অপারেশনগুলি এত তাড়াতাড়ি প্রয়োগ হয়? আমি ভাবছি সেখানেও সারি পুনরাবৃত্তির দ্বারা কিছুটা সারি থাকতে হবে।

আমার ক্ষেত্রে কীভাবে এটিরোগগুলি ব্যবহার করবেন না তা আমি বুঝতে পারি না (এটি আমি ভবিষ্যতের প্রশ্নের জন্য সংরক্ষণ করব)। অতএব, আপনি যদি ধারাবাহিকভাবে এই পুনরাবৃত্তিটি এড়াতে সক্ষম হন তবে আমি শ্রবণকে প্রশংসা করব। আমি পৃথক ডেটাফ্রেমে ডেটা ভিত্তিক গণনা করছি। ধন্যবাদ!

--- সম্পাদনা করুন: আমি যা চালাতে চাই তার সরলীকৃত সংস্করণটি নীচে যুক্ত করা হয়েছে ---

import pandas as pd
import numpy as np

#%% Create the original tables
t1 = {'letter':['a','b'],
      'number1':[50,-10]}

t2 = {'letter':['a','a','b','b'],
      'number2':[0.2,0.5,0.1,0.4]}

table1 = pd.DataFrame(t1)
table2 = pd.DataFrame(t2)

#%% Create the body of the new table
table3 = pd.DataFrame(np.nan, columns=['letter','number2'], index=[0])

#%% Iterate through filtering relevant data, optimizing, returning info
for row_index, row in table1.iterrows():   
    t2info = table2[table2.letter == row['letter']].reset_index()
    table3.ix[row_index,] = optimize(t2info,row['number1'])

#%% Define optimization
def optimize(t2info, t1info):
    calculation = []
    for index, r in t2info.iterrows():
        calculation.append(r['number2']*t1info)
    maxrow = calculation.index(max(calculation))
    return t2info.ix[maxrow]

7
applyভেক্টরাইজড নয়। iterrowsএটি আরও খারাপ হিসাবে এটি সমস্ত কিছু বাক্স করে দেয় (যা 'পারফের সাথে পৃথক হয় apply)। আপনার iterrowsখুব খুব কম পরিস্থিতিতে ব্যবহার করা উচিত । আইএমএইচও কখনও নয়। আপনি আসলে কী করছেন তা দেখান iterrows
জেফ

4
পরিবর্তে আপনি যে ইস্যুটির সাথে লিঙ্ক করেছেন এটির একটি বক্সিংয়ের সাথে DatetimeIndexকরা Timestamps(পাইথন স্পেসে প্রয়োগ করা হয়েছিল), এবং এটি মাস্টার হিসাবে অনেক উন্নত হয়েছে।
জেফ

4
আরও পূর্ণ আলোচনার জন্য এই সমস্যাটি দেখুন: github.com/pydata/pandas/issues/7194
জেফ

: নির্দিষ্ট প্রশ্ন লিঙ্ক করুন (এই এক সাধারণ থাকবো) stackoverflow.com/questions/24875096/...
KieranPC

দয়া করে এটিরোজ () ব্যবহারের প্রস্তাব দিবেন না। এটি পান্ডার ইতিহাসের সবচেয়ে খারাপ এন্টি-প্যাটার্নের একটি স্পষ্ট সক্ষম enable
সিএস 95

উত্তর:


188

সাধারণত, iterrowsশুধুমাত্র খুব খুব নির্দিষ্ট ক্ষেত্রে ব্যবহার করা উচিত। এটি বিভিন্ন ক্রিয়াকলাপ সম্পাদনের জন্য অগ্রাধিকারের সাধারণ ক্রম:

1) vectorization
2) using a custom cython routine
3) apply
    a) reductions that can be performed in cython
    b) iteration in python space
4) itertuples
5) iterrows
6) updating an empty frame (e.g. using loc one-row-at-a-time)

একটি কাস্টম সিথন রুটিন ব্যবহার করা সাধারণত খুব জটিল হয়, তাই আপাতত এটি এড়ানো যাক।

1) ভেক্টরাইজেশন হ'ল সর্বদা, সর্বদা প্রথম এবং সেরা পছন্দ। তবে, ছোট ছোট কয়েকটি মামলা রয়েছে (সাধারণত একটি পুনরাবৃত্তি জড়িত) যা সুস্পষ্ট উপায়ে ভেক্টরাইজ করা যায় না। তদ্ব্যতীত, একটি ছোট্টতে DataFrame, অন্যান্য পদ্ধতি ব্যবহার করা আরও দ্রুত হতে পারে।

3) apply সাধারণত সিথন স্পেসে কোনও পুনরুক্তিকারক দ্বারা পরিচালনা করা যায়। এটি প্যান্ডাস দ্বারা অভ্যন্তরীণভাবে পরিচালিত হয়, যদিও এটি applyঅভিব্যক্তির ভিতরে কী চলছে তার উপর নির্ভর করে । উদাহরণস্বরূপ, df.apply(lambda x: np.sum(x))খুব দ্রুত মৃত্যুদন্ড কার্যকর করা হবে, যদিও df.sum(1)এটি আরও ভাল। তবে df.apply(lambda x: x['b'] + 1)পাইথন স্পেসে এর মতো কিছু কার্যকর করা হবে এবং ফলস্বরূপ অনেক ধীর।

4) itertuplesএকটি এ ডেটা বক্স করে না Series। এটি কেবল টিপলস আকারে ডেটা ফেরত দেয়।

5) iterrowsডেটা বাক্সে একটি Series। আপনার যদি সত্যিই এটির প্রয়োজন না হয় তবে অন্য একটি পদ্ধতি ব্যবহার করুন।

6) এ-সময়ে-একবারে একটি খালি ফ্রেম আপডেট করা। আমি এই পদ্ধতিটি WAY খুব বেশি ব্যবহৃত দেখেছি। এটি এখন পর্যন্ত সবচেয়ে ধীর। এটি সম্ভবত সাধারণ জায়গা (এবং কিছু অজগর কাঠামোর জন্য যুক্তিসঙ্গতভাবে দ্রুত) তবে DataFrameএটি সূচকে ন্যায্য সংখ্যক চেক করে, তাই এটি একবারে একটি সারি আপডেট করতে সর্বদা খুব ধীর হবে। নতুন কাঠামো তৈরি করা আরও ভাল concat


4
হ্যাঁ, আমি 6 নম্বর (এবং 5) ব্যবহার করেছি। আমি কিছু শিখতে পেয়েছি। এটি কোনও আপেক্ষিক শিক্ষানবিসের কাছে সুস্পষ্ট পছন্দ বলে মনে হয়।
কিয়েরানপিসি

4
আমার অভিজ্ঞতায় 3, 4 এবং 5 এর মধ্যে পার্থক্যটি ব্যবহারের ক্ষেত্রে নির্ভর করে সীমাবদ্ধ।
ইয়ানস

8
আমি এই নোটবুকে রানটাইমগুলি পরীক্ষা করার চেষ্টা করেছি । একরকম itertuplesদ্রুত চেয়ে apply:(
Dimgold

4
pd.DataFrame.applyপ্রায়শই ধীর হয় itertuples। উপরন্তু, এটা মূল্য তালিকা comprehensions বিবেচনা করা, map, দুর্বল নামে np.vectorizeএবং numbaজন্য (কোন বিশেষ আদেশ) অ vectorisable গণনার যেমন দেখতে এই উত্তর
jpp

4
@ জেফ, কৌতূহলবশত, আপনি এখানে তালিকা বোঝার যোগ করেননি কেন? যদিও এটি সত্য যে তারা সূচিপত্র প্রান্তিককরণ বা অনুপস্থিত ডেটা পরিচালনা করে না (যদি না আপনি চেষ্টা করে একটি ফাংশন ব্যবহার করেন) তবে তারা প্রচুর ব্যবহারের ক্ষেত্রে (স্ট্রিং / রেজেক্স স্টাফ) ভাল যেখানে প্যান্ডাস পদ্ধতিতে ভেক্টরাইজড নেই ( শব্দটির সত্যিকার অর্থে) বাস্তবায়ন। আপনার কি মনে হয় এলসিগুলি পান্ডার প্রয়োগের জন্য একটি দ্রুত, নিম্ন ওভারহেড বিকল্প এবং অনেকগুলি পান্ডার স্ট্রিং ফাংশন?
cs95

17

বিভিন্ন কারণে ভ্যানিলা পাইথনের স্ক্যালার অপারেশনের চেয়ে নম্পি এবং পান্ডাসে ভেক্টর অপারেশনগুলি অনেক দ্রুত :

  • এমোরিটাইজড টাইপ লুকিং : পাইথন হ'ল গতিশীল টাইপ করা একটি ভাষা, সুতরাং অ্যারেতে প্রতিটি উপাদানগুলির জন্য রানটাইম ওভারহেড থাকে। তবে, নম্পি (এবং এইভাবে পান্ডাস) সি (প্রায়শই সিথনের মাধ্যমে) গণনা সম্পাদন করে। অ্যারের ধরণটি কেবল পুনরাবৃত্তির শুরুতে নির্ধারিত হয়; এই সঞ্চয় একাই সবচেয়ে বড় জয়।

  • উন্নততর ক্যাচিং : সি অ্যারের উপরে আইট্রেট করা ক্যাশে-বান্ধব এবং এইভাবে খুব দ্রুত। একটি পান্ডাস ডেটা ফ্রেম হ'ল "কলাম-ওরিয়েন্টেড টেবিল", যার অর্থ প্রতিটি কলাম সত্যই কেবল একটি অ্যারে। সুতরাং আপনি ডেটাফ্রেমে (স্থানীয় কলামের সমস্ত উপাদানগুলির সংমিশ্রণের মতো) কাজ করতে সক্ষম নেটিভ ক্রিয়াকলাপে কয়েকটি ক্যাশে মিস করতে চলেছে।

  • সমান্তরালতার আরও সুযোগ : সিমডি নির্দেশের মাধ্যমে একটি সাধারণ সি অ্যারে চালিত হতে পারে। নম্পির কিছু অংশ আপনার সিপিইউ এবং ইনস্টলেশন প্রক্রিয়ার উপর নির্ভর করে সিমডি সক্ষম করে। সমান্তরালতার উপকারগুলি স্থির টাইপিং এবং আরও ভাল ক্যাচিংয়ের মতো নাটকীয় হবে না তবে তারা এখনও শক্ত জয় solid

গল্পটির নৈতিকতা: নম্পি এবং পান্ডায় ভেক্টর অপারেশন ব্যবহার করুন। তারা পাইথনের স্কেলার অপারেশনের চেয়ে দ্রুত কারণ সাধারণ কারণেই এই অপারেশনগুলি হ'ল কোনও সি প্রোগ্রামার হাতে-কলমে লিখেছিল। (এম্বেড থাকা সিমডি নির্দেশাবলী সহ সুস্পষ্ট লুপের চেয়ে অ্যারে ধারণাটি পড়া খুব সহজ)


11

আপনার সমস্যাটি করার উপায় এখানে। এটি সব ভেক্টরাইজড।

In [58]: df = table1.merge(table2,on='letter')

In [59]: df['calc'] = df['number1']*df['number2']

In [60]: df
Out[60]: 
  letter  number1  number2  calc
0      a       50      0.2    10
1      a       50      0.5    25
2      b      -10      0.1    -1
3      b      -10      0.4    -4

In [61]: df.groupby('letter')['calc'].max()
Out[61]: 
letter
a         25
b         -1
Name: calc, dtype: float64

In [62]: df.groupby('letter')['calc'].idxmax()
Out[62]: 
letter
a         1
b         2
Name: calc, dtype: int64

In [63]: df.loc[df.groupby('letter')['calc'].idxmax()]
Out[63]: 
  letter  number1  number2  calc
1      a       50      0.5    25
2      b      -10      0.1    -1

খুব পরিষ্কার উত্তর ধন্যবাদ। আমি একীভূত করার চেষ্টা করব তবে আমার সন্দেহ রয়েছে কারণ আমার তখন 5 বিলিয়ন সারি (2.5 মিলিয়ন * 2000) হবে। : এখানে: এই প্রশ্ন সাধারণ যেতে চাইলে আমি একটি নির্দিষ্ট প্র: আপনি এক জানি আমি, একটি বিকল্প এই দৈত্য টেবিল এড়াতে দেখে খুশি হতে চাই তৈরি করেছি stackoverflow.com/questions/24875096/...
KieranPC

4
এটি কার্টেসিয়ান পণ্য তৈরি করে না - এটি একটি সঙ্কোচিত স্থান এবং এটি বেশ স্মৃতিশক্তি দক্ষ। আপনি যা করছেন তা খুব মানক সমস্যা। একবার চেষ্টা করে দেখ. (আপনার লিঙ্কযুক্ত প্রশ্নের খুব অনুরূপ দ্রবণ রয়েছে)
জেফ

7

আর একটি বিকল্প ব্যবহার করা হয় to_records(), যা উভয়ের চেয়ে দ্রুত itertuplesএবং iterrows

তবে আপনার ক্ষেত্রে অন্যান্য ধরণের উন্নতির জন্য অনেক জায়গা রয়েছে।

এখানে আমার চূড়ান্ত অপ্টিমাইজড সংস্করণ

def iterthrough():
    ret = []
    grouped = table2.groupby('letter', sort=False)
    t2info = table2.to_records()
    for index, letter, n1 in table1.to_records():
        t2 = t2info[grouped.groups[letter].values]
        # np.multiply is in general faster than "x * y"
        maxrow = np.multiply(t2.number2, n1).argmax()
        # `[1:]`  removes the index column
        ret.append(t2[maxrow].tolist()[1:])
    global table3
    table3 = pd.DataFrame(ret, columns=('letter', 'number2'))

বেঞ্চমার্ক পরীক্ষা:

-- iterrows() --
100 loops, best of 3: 12.7 ms per loop
  letter  number2
0      a      0.5
1      b      0.1
2      c      5.0
3      d      4.0

-- itertuple() --
100 loops, best of 3: 12.3 ms per loop

-- to_records() --
100 loops, best of 3: 7.29 ms per loop

-- Use group by --
100 loops, best of 3: 4.07 ms per loop
  letter  number2
1      a      0.5
2      b      0.1
4      c      5.0
5      d      4.0

-- Avoid multiplication --
1000 loops, best of 3: 1.39 ms per loop
  letter  number2
0      a      0.5
1      b      0.1
2      c      5.0
3      d      4.0

সম্পূর্ণ কোড:

import pandas as pd
import numpy as np

#%% Create the original tables
t1 = {'letter':['a','b','c','d'],
      'number1':[50,-10,.5,3]}

t2 = {'letter':['a','a','b','b','c','d','c'],
      'number2':[0.2,0.5,0.1,0.4,5,4,1]}

table1 = pd.DataFrame(t1)
table2 = pd.DataFrame(t2)

#%% Create the body of the new table
table3 = pd.DataFrame(np.nan, columns=['letter','number2'], index=table1.index)


print('\n-- iterrows() --')

def optimize(t2info, t1info):
    calculation = []
    for index, r in t2info.iterrows():
        calculation.append(r['number2'] * t1info)
    maxrow_in_t2 = calculation.index(max(calculation))
    return t2info.loc[maxrow_in_t2]

#%% Iterate through filtering relevant data, optimizing, returning info
def iterthrough():
    for row_index, row in table1.iterrows():   
        t2info = table2[table2.letter == row['letter']].reset_index()
        table3.iloc[row_index,:] = optimize(t2info, row['number1'])

%timeit iterthrough()
print(table3)

print('\n-- itertuple() --')
def optimize(t2info, n1):
    calculation = []
    for index, letter, n2 in t2info.itertuples():
        calculation.append(n2 * n1)
    maxrow = calculation.index(max(calculation))
    return t2info.iloc[maxrow]

def iterthrough():
    for row_index, letter, n1 in table1.itertuples():   
        t2info = table2[table2.letter == letter]
        table3.iloc[row_index,:] = optimize(t2info, n1)

%timeit iterthrough()


print('\n-- to_records() --')
def optimize(t2info, n1):
    calculation = []
    for index, letter, n2 in t2info.to_records():
        calculation.append(n2 * n1)
    maxrow = calculation.index(max(calculation))
    return t2info.iloc[maxrow]

def iterthrough():
    for row_index, letter, n1 in table1.to_records():   
        t2info = table2[table2.letter == letter]
        table3.iloc[row_index,:] = optimize(t2info, n1)

%timeit iterthrough()

print('\n-- Use group by --')

def iterthrough():
    ret = []
    grouped = table2.groupby('letter', sort=False)
    for index, letter, n1 in table1.to_records():
        t2 = table2.iloc[grouped.groups[letter]]
        calculation = t2.number2 * n1
        maxrow = calculation.argsort().iloc[-1]
        ret.append(t2.iloc[maxrow])
    global table3
    table3 = pd.DataFrame(ret)

%timeit iterthrough()
print(table3)

print('\n-- Even Faster --')
def iterthrough():
    ret = []
    grouped = table2.groupby('letter', sort=False)
    t2info = table2.to_records()
    for index, letter, n1 in table1.to_records():
        t2 = t2info[grouped.groups[letter].values]
        maxrow = np.multiply(t2.number2, n1).argmax()
        # `[1:]`  removes the index column
        ret.append(t2[maxrow].tolist()[1:])
    global table3
    table3 = pd.DataFrame(ret, columns=('letter', 'number2'))

%timeit iterthrough()
print(table3)

চূড়ান্ত সংস্করণটি মূল কোডের চেয়ে প্রায় 10x দ্রুত। কৌশলটি হ'ল:

  1. groupbyমানের সাথে বারবার তুলনা এড়াতে ব্যবহার করুন ।
  2. to_recordsকাঁচা numpy.records অবজেক্ট অ্যাক্সেস করতে ব্যবহার করুন ।
  3. যতক্ষণ না আপনি সমস্ত ডেটা সংকলন করেন ডেটা ফ্রেমে অপারেট করবেন না।

0

হ্যাঁ, পান্ডাস ইটারটুপলস () এর এরো () এর চেয়ে দ্রুত। আপনি ডকুমেন্টেশনটি উল্লেখ করতে পারেন: https://pandas.pydata.org/pandas-docs/stable/references/api/pandas.DataFrame.iterrows.html

"সারিগুলিতে পুনরাবৃত্তি করার সময় ধরণের টাইপগুলি সংরক্ষণ করার জন্য, এটির ব্যবহারশক্তি ব্যবহার করা ভাল () যা মানগুলির নামের তালিকায় ফিরে আসে এবং এটি সাধারণত ইরোরোর চেয়ে দ্রুত হয়" "


আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.