팬더 뱃놀이는 경기력에 문제가 있습니까?
저는 판다의 화살을 사용할 때 성능이 매우 떨어지는 것을 발견했습니다.
특정 크기의 데이터(2-3백만 개의 행으로 작업 중)에 대해 이 기능을 피해야 합니까?
GitHub에 대한 이 토론을 통해 데이터 프레임에서 dtype을 혼합할 때 발생하는 것으로 믿었지만 아래의 간단한 예는 하나의 dtype(float64)을 사용할 때에도 존재한다는 것을 보여줍니다.내 컴퓨터에서는 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]
일반적으로.iterrows
매우, 매우 구체적인 경우에만 사용해야 합니다.다음은 다양한 작업의 수행에 대한 일반적인 우선 순위입니다.
- 벡터화
- 사용자 지정 Cython 루틴 사용
- 적용합니다.
- 사이톤에서 수행할 수 있는 감소
- Python 공간에서 반복
- 반복적인 튜플
- 연속 행
- 빈 프레임 업데이트(예: 한 번에 한 행씩 loc 사용)
사용자 지정 Cython 루틴을 사용하는 것은 일반적으로 너무 복잡하므로 지금은 생략합니다.
벡터화는 항상, 항상 첫 번째이자 최선의 선택입니다.그러나 명확한 방법으로 벡터화할 수 없는 경우(일반적으로 재발을 포함)가 있습니다.게다가, 작은 물고기 위에.
DataFrame
다른 방법을 사용하는 것이 더 빠를 수 있습니다.apply
일반적으로 싸이톤 공간의 반복자가 처리할 수 있습니다.이것은 내부적으로 판다에 의해 처리됩니다, 비록 그것은 내부에서 무슨 일이 일어나고 있는지에 달려있습니다.apply
표현.예를들면,df.apply(lambda x: np.sum(x))
물론 꽤 빨리 처형되겠지만,df.sum(1)
훨씬 더 좋습니다.그러나 비슷한 것.df.apply(lambda x: x['b'] + 1)
Python 공간에서 실행되므로 속도가 훨씬 느려집니다.itertuples
데이터를 상자에 넣지 않습니다.Series
데이터를 튜플 형태로 반환합니다.iterrows
데이터를 상자에 넣습니까?Series
이것이 꼭 필요한 경우가 아니라면 다른 방법을 사용하십시오.빈 프레임을 한 번에 한 행씩 업데이트합니다.저는 이 방법이 너무 많이 사용되는 것을 보았습니다.그것은 단연코 가장 느립니다.그것은 아마도 흔한 장소일 것입니다 (그리고 일부 파이썬 구조에서는 상당히 빠릅니다), 그러나
DataFrame
에서는 인덱싱에 대해 상당히 많은 검사를 수행하므로 한 번에 행을 업데이트하는 속도가 항상 느려집니다., 새운구을것이훨낫고씬만드는로조물,▁much,concat
.
Numpy 및 panda의 벡터 연산은 바닐라 파이썬의 스칼라 연산보다 몇 가지 이유로 훨씬 빠릅니다.
상각 유형 조회:Python은 동적으로 입력되는 언어이므로 배열의 각 요소에 대한 런타임 오버헤드가 있습니다.그러나 Numpy(따라서 판다)는 C(종종 사이톤을 통해)에서 계산을 수행합니다.어레이의 유형은 반복이 시작될 때만 결정됩니다. 이러한 절감 효과만으로도 가장 큰 이점 중 하나입니다.
향상된 캐슁:C 어레이를 통해 반복하는 것은 캐시 친화적이므로 매우 빠릅니다.판다 데이터 프레임은 "열 지향 테이블"이며, 이는 각 열이 실제로 배열에 불과하다는 것을 의미합니다.따라서 데이터 프레임에 대해 수행할 수 있는 기본 작업(한 열의 모든 요소 합계 등)에서는 캐시 누락이 거의 없습니다.
병렬화를 위한 더 많은 기회:SIMD 지침을 통해 간단한 C 배열을 작동할 수 있습니다.CPU 및 설치 프로세스에 따라 Numpy의 일부에서 SIMD를 사용할 수 있습니다.병렬 처리의 이점은 정적 타이핑과 더 나은 캐싱만큼 극적이지는 않겠지만 그래도 확실한 승리입니다.
이야기의 교훈: 눔피와 판다의 벡터 연산을 사용합니다.이러한 연산은 C 프로그래머가 손으로 작성한 것과 정확히 일치하기 때문에 Python의 스칼라 연산보다 빠릅니다. (배열 개념이 내장된 SIMD 명령어가 있는 명시적 루프보다 훨씬 읽기 쉽다는 점을 제외하면)
당신의 문제를 해결하는 방법이 여기 있습니다.이것은 모두 벡터화되어 있습니다.
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
연속 행을 사용하지 마십시오!
...또는iteritems
또는itertuples
진짜, 하지 마.가능한 경우 코드를 벡터화합니다.못 믿겠으면 제프에게 물어보세요.
DataFrame을 통해 반복할 수 있는 합법적인 사용 사례가 있다는 것은 인정하지만, 반복할 수 있는 훨씬 더 나은 대안이 있습니다.iter*
의 기능, 즉 가,, 즉▁functions▁family,
종종 너무 많은 초보자들이 판다들에게 코드와 관련된 질문들을 합니다.iterrows
이 새로운 사용자들은 벡터화의 개념에 익숙하지 않을 가능성이 높기 때문에, 그들은 그들의 문제를 해결하는 코드를 루프나 다른 반복적인 루틴을 포함하는 것으로 상상합니다.반복하는 법도 모르면서, 그들은 보통 이 질문에 도달하고 모든 잘못된 것들을 배웁니다.
지지하는 주장
반복 시 설명서 페이지에는 다음과 같은 내용의 빨간색 경고 상자가 표시됩니다.
판다 개체를 통해 반복하는 것은 일반적으로 느립니다.대부분의 경우 행을 통해 수동으로 반복할 필요가 없습니다 [...].
그래도 납득이 가지 않는다면 여기 제 게시물에서 가져온 두 개의 열 "A + B"를 추가하기 위한 벡터화 기술과 비벡터화 기술 간의 성능 비교를 살펴보십시오.
참고로 벤치마킹 코드입니다.iterrows
그것은 단연코 가장 나쁜 것이며, 다른 반복적인 방법들도 훨씬 더 좋지 않다는 것을 지적할 가치가 있습니다.
맨 아래의 선은 최대 성능을 짜내기 위해 NumPy와 많이 혼합되는 팬더 스타일인 Numpandas로 쓰여진 기능을 측정합니다.당신이 무엇을 하고 있는지 알지 못하는 한 numpandas 코드를 쓰는 것은 피해야 합니다. 선호하는 를 선호함)를 합니다.vec
1파운드가 vec_numpy
).
결론적으로
항상 벡터화를 시도합니다.가능한 것은 때로문제데특따성항라가것오상찾보다 더 인 루틴을 .iterrows
극히 적은 수의 행을 처리할 때의 편리함 외에는 이에 대한 합법적인 사용 사례가 거의 없습니다. 그렇지 않으면 코드가 몇 시간 동안 실행되는 동안 많은 대기 시간을 준비해야 합니다.
코드를 해결하기 위한 최상의 방법/벡터화된 루틴을 결정하려면 아래 링크를 확인하십시오.
10분간 판다 및 필수 기본 기능 - Panda 및 벡터화*/사이톤화된 기능의 라이브러리를 소개하는 유용한 링크입니다.
성능 향상 - 표준 Panda 작동 개선에 대한 설명서의 입문서
은 다옵션다같다니습과음은을 사용하는 것입니다.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)
최종 버전은 원래 코드보다 거의 10배 빠릅니다.전략은 다음과 같습니다.
- 사용하다
groupby
값의 반복적인 비교를 방지합니다. - 사용하다
to_records
원시 numpy.dll 개체에 액세스합니다. - 모든 데이터를 컴파일할 때까지 DataFrame에서 작동하지 마십시오.
벤치마크
이름별로 행 필드를 반복하고 액세스해야 하는 경우 열 이름을 목록에 저장하고 데이터 프레임을 NumPy 배열로 변환합니다.
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})
columns = list(dfa.columns)
dfa = dfa.values
start = time.time()
i=0
for row in dfa:
blablabla = row[columns.index('s1')]
i+=1
end = time.time()
print (end - start)
0.9485495090484619
예, Pandasite tuffle()이 iterrow()보다 빠릅니다.당신은 판다라는 문서를 참조할 수 있습니다.DataFrame.iterrows
행을 반복하는 동안 유형을 보존하려면 이름이 지정된 값의 튜플을 반환하고 일반적으로 반복 행보다 빠른 tupples()를 사용하는 것이 좋습니다.
언급URL : https://stackoverflow.com/questions/24870953/does-pandas-iterrows-have-performance-issues
'programing' 카테고리의 다른 글
오류로 인한 Gulp Watch 깨짐 (0) | 2023.07.25 |
---|---|
매우 큰 테이블에서 Mysql 개수 성능 (0) | 2023.07.25 |
열을 Oracle db의 동일한 테이블 내의 다른 열로 복사합니다.어떤 데이터가 어디에 저장되는지 지정해야 합니까? (0) | 2023.07.25 |
PowerShell에서 "<" 입력 리디렉션이 구현되지 않는 이유는 무엇입니까? (0) | 2023.07.25 |
C의 이중 부정 : 0/1을 반환하는 것이 보장됩니까? (0) | 2023.07.25 |