code

Pandas DataFrame 성능

codestyles 2020. 12. 1. 08:02
반응형

Pandas DataFrame 성능


Pandas는 정말 훌륭하지만 Pandas.DataFrame에서 값을 검색하는 것이 얼마나 비효율적인지 정말 놀랐습니다. 다음 장난감 예제에서는 DataFrame.iloc 메서드도 사전보다 100 배 이상 느립니다.

질문 : 여기서 교훈은 사전이 값을 찾는 더 좋은 방법이라는 것입니까? 예, 정확히 그것이 그들이 만든 것임을 이해합니다. 하지만 DataFrame 조회 성능에 대해 내가 놓친 것이 있는지 궁금합니다.

나는이 질문이 "요구하는 것"보다 "즐거운"질문이라는 것을 알고 있지만 이에 대한 통찰력이나 관점을 제공하는 대답을 받아 들일 것입니다. 감사.

import timeit

setup = '''
import numpy, pandas
df = pandas.DataFrame(numpy.zeros(shape=[10, 10]))
dictionary = df.to_dict()
'''

f = ['value = dictionary[5][5]', 'value = df.loc[5, 5]', 'value = df.iloc[5, 5]']

for func in f:
    print func
    print min(timeit.Timer(func, setup).repeat(3, 100000))

값 = 사전 [5] [5]

0.130625009537

값 = df.loc [5, 5]

19.4681699276

값 = df.iloc [5, 5]

17.2575249672


자전거가 자동차에 해당하는 것처럼 dict는 DataFrame에 있습니다. 자전거를 타고 10 피트 페달을 밟으면 시동을 걸거나 기어를 넣는 등의 작업을 할 수 있습니다.하지만 1 마일을 가야한다면 차가 이깁니다.

작은 특정 목적의 경우 사전이 더 빠를 수 있습니다. 그리고 그것이 당신이 필요한 전부라면, 확실히 dict를 사용하십시오! 그러나 DataFrame의 강력 함과 고급 스러움이 필요하거나 원한다면 dict는 대체 할 수 없습니다. 데이터 구조가 먼저 요구 사항을 충족하지 않으면 속도를 비교하는 것은 의미가 없습니다.

예를 들어보다 구체적으로 말하자면 dict는 열에 액세스하는 데 적합하지만 행에 액세스하는 데는 그리 편리하지 않습니다.

import timeit

setup = '''
import numpy, pandas
df = pandas.DataFrame(numpy.zeros(shape=[10, 1000]))
dictionary = df.to_dict()
'''

# f = ['value = dictionary[5][5]', 'value = df.loc[5, 5]', 'value = df.iloc[5, 5]']
f = ['value = [val[5] for col,val in dictionary.items()]', 'value = df.loc[5]', 'value = df.iloc[5]']

for func in f:
    print(func)
    print(min(timeit.Timer(func, setup).repeat(3, 100000)))

수확량

value = [val[5] for col,val in dictionary.iteritems()]
25.5416321754
value = df.loc[5]
5.68071913719
value = df.iloc[5]
4.56006002426

따라서 목록의 사전은 행 검색에서 df.iloc. 컬럼 수가 증가할수록 속도 부족이 커집니다. (열의 수는 자전거 비유의 피트 수와 같습니다. 거리가 길수록 차는 더 편리해집니다 ...)

이것은 목록의 사전이 DataFrame보다 덜 편리하거나 느릴 때의 한 예일뿐입니다.

또 다른 예는 행에 대한 DatetimeIndex가 있고 특정 날짜 사이의 모든 행을 선택하려는 경우입니다. DataFrame을 사용하면

df.loc['2000-1-1':'2000-3-31']

목록의 딕셔너리를 사용한다면 쉬운 아날로그는 없습니다. 그리고 올바른 행을 선택하는 데 사용해야하는 Python 루프는 DataFrame에 비해 다시 매우 느립니다.


지금은 성능 차이가 훨씬 작아 보입니다 (0.21.1-원래 예제에서 Pandas 버전이 무엇인지 잊어 버렸습니다). 사전 액세스와 .loc감소 된 (약 335 배에서 126 배 더 느림) 사이의 성능 차이뿐만 아니라 loc( iloc)는 현재 at( iat) 보다 두 배 미만 느립니다 .

In [1]: import numpy, pandas
   ...:    ...: df = pandas.DataFrame(numpy.zeros(shape=[10, 10]))
   ...:    ...: dictionary = df.to_dict()
   ...: 

In [2]: %timeit value = dictionary[5][5]
85.5 ns ± 0.336 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

In [3]: %timeit value = df.loc[5, 5]
10.8 µs ± 137 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

In [4]: %timeit value = df.at[5, 5]
6.87 µs ± 64.9 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

In [5]: %timeit value = df.iloc[5, 5]
14.9 µs ± 114 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

In [6]: %timeit value = df.iat[5, 5]
9.89 µs ± 54.7 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

In [7]: print(pandas.__version__)
0.21.1

---- 아래 원본 답변 ----

스칼라 연산 을 사용 at하거나 사용하는 경우 +1 iat. 벤치 마크 예 :

In [1]: import numpy, pandas
   ...: df = pandas.DataFrame(numpy.zeros(shape=[10, 10]))
   ...: dictionary = df.to_dict()

In [2]: %timeit value = dictionary[5][5]
The slowest run took 34.06 times longer than the fastest. This could mean that an intermediate result is being cached 
1000000 loops, best of 3: 310 ns per loop

In [4]: %timeit value = df.loc[5, 5]
10000 loops, best of 3: 104 µs per loop

In [5]: %timeit value = df.at[5, 5]
The slowest run took 6.59 times longer than the fastest. This could mean that an intermediate result is being cached 
100000 loops, best of 3: 9.26 µs per loop

In [6]: %timeit value = df.iloc[5, 5]
10000 loops, best of 3: 98.8 µs per loop

In [7]: %timeit value = df.iat[5, 5]
The slowest run took 6.67 times longer than the fastest. This could mean that an intermediate result is being cached 
100000 loops, best of 3: 9.58 µs per loop

at( iat)를 사용하는 것이 loc( iloc) 보다 약 10 배 빠른 것 같습니다 .


같은 문제가 발생했습니다. at개선 하는 사용할 수 있습니다 .

"Since indexing with [] must handle a lot of cases (single-label access, slicing, boolean indexing, etc.), it has a bit of overhead in order to figure out what you’re asking for. If you only want to access a scalar value, the fastest way is to use the at and iat methods, which are implemented on all of the data structures."

see official reference http://pandas.pydata.org/pandas-docs/stable/indexing.html chapter "Fast scalar value getting and setting"


I think the fastest way of accessing a cell, is

df.get_value(row,column)
df.set_value(row,column,value) 

Both are faster than (I think)

df.iat(...) 
df.at(...)

I experienced different phenomenon about accessing the dataframe row. test this simple example on dataframe about 10,000,000 rows. dictionary rocks.

def testRow(go):
    go_dict = go.to_dict()
    times = 100000
    ot= time.time()
    for i in range(times):
        go.iloc[100,:]
    nt = time.time()
    print('for iloc {}'.format(nt-ot))
    ot= time.time()
    for i in range(times):
        go.loc[100,2]
    nt = time.time()
    print('for loc {}'.format(nt-ot))
    ot= time.time()
    for i in range(times):
        [val[100] for col,val in go_dict.iteritems()]
    nt = time.time()
    print('for dict {}'.format(nt-ot))

참고URL : https://stackoverflow.com/questions/22084338/pandas-dataframe-performance

반응형