질문자 :Roman
Pandas의 DataFrame
있습니다.
import pandas as pd inp = [{'c1':10, 'c2':100}, {'c1':11,'c2':110}, {'c1':12,'c2':120}] df = pd.DataFrame(inp) print df
산출:
c1 c2 0 10 100 1 11 110 2 12 120
이제 이 프레임의 행을 반복하고 싶습니다. 모든 행에 대해 열 이름으로 해당 요소(셀의 값)에 액세스할 수 있기를 원합니다. 예를 들어:
for row in df.rows: print row['c1'], row['c2']
Pandas에서 그렇게 할 수 있습니까?
이 비슷한 질문을 찾았습니다. 그러나 그것은 나에게 필요한 답을 주지 않습니다. 예를 들어 다음을 사용하는 것이 좋습니다.
for date, row in df.T.iteritems():
또는
for row in df.iterrows():
row
개체가 무엇이며 어떻게 작업할 수 있는지 이해하지 못합니다.
DataFrame.iterrows
는 인덱스와 행(시리즈로)을 모두 생성하는 생성기입니다.
import pandas as pd df = pd.DataFrame({'c1': [10, 11, 12], 'c2': [100, 110, 120]}) for index, row in df.iterrows(): print(row['c1'], row['c2'])
10 100 11 110 12 120
waitingkuoPandas에서 DataFrame의 행을 반복하는 방법은 무엇입니까?
답변: 하지 마세요 * !
Pandas의 반복은 안티 패턴이며 다른 모든 옵션을 소진했을 때만 수행해야 하는 것입니다. iter
"가 포함된 함수를 수천 행 이상에 사용해서는 안 됩니다. 그렇지 않으면 많은 기다림에 익숙해져야 합니다.
DataFrame을 인쇄하시겠습니까? DataFrame.to_string()
사용하십시오.
계산을 하시겠습니까? 이 경우 다음 순서로 메서드를 검색합니다( 여기 에서 수정된 목록).
- 벡터화
- 사이썬 루틴
- 목록 이해(루프
for
-
DataFrame.apply()
: i) Cython에서 수행할 수 있는 축소, ii) Python 공간에서 반복 -
DataFrame.itertuples()
및 iteritems()
-
DataFrame.iterrows()
iterrows
및 itertuples
(둘 다 이 질문에 대한 답변에서 많은 표를 얻음)는 순차 처리를 위한 행 객체/이름 튜플을 생성하는 것과 같이 매우 드문 상황에서 사용해야 합니다.
권위에 호소
반복 문서 페이지 에는 다음과 같은 거대한 빨간색 경고 상자가 있습니다.
pandas 객체를 반복하는 것은 일반적으로 느립니다. 많은 경우 행을 수동으로 반복할 필요가 없습니다[...].
* 실제로는 "하지마"보다 조금 더 복잡합니다. df.iterrows()
이 질문에 대한 정답이지만 "작업을 벡터화"하는 것이 더 좋습니다. 반복을 피할 수 없는 상황이 있음을 인정합니다(예: 결과가 이전 행에 대해 계산된 값에 따라 달라지는 일부 작업). 그러나 언제인지 알기 위해서는 라이브러리에 어느 정도 익숙해야 합니다. 반복 솔루션이 필요한지 여부가 확실하지 않은 경우에는 그렇지 않을 수 있습니다. 추신: 이 답변을 작성하는 이유에 대해 자세히 알아보려면 맨 아래로 건너뜁니다.
많은 기본 연산과 계산이 팬더에 의해 "벡터화"됩니다(NumPy 또는 Cythonized 함수를 통해). 여기에는 산술, 비교, (대부분) 축소, 형태 변경(예: 피벗), 조인 및 그룹화 작업이 포함됩니다. 필수 기본 기능 에 대한 문서를 살펴보고 문제에 적합한 벡터화 방법을 찾으십시오.
존재하지 않는 경우 사용자 정의 Cython 확장을 사용하여 자유롭게 작성하십시오.
1) 사용 가능한 벡터화된 솔루션이 없는 경우, 2) 성능이 중요하지만 코드를 암호화하는 번거로움을 겪을 만큼 중요하지 않은 경우, 3) 요소별 변환을 수행하려는 경우 목록 이해가 다음 호출 포트여야 합니다. 당신의 코드에. 이 증거의 좋은 금액 이 지능형리스트가 충분히 빠른 (심지어 때로는 빨리) 많은 일반 팬더 작업에 있습니다 제안하는가.
공식은 간단하고,
# Iterating over one column - `f` is some function that processes your data result = [f(x) for x in df['col']] # Iterating over two columns, use `zip` result = [f(x, y) for x, y in zip(df['col1'], df['col2'])] # Iterating over multiple columns - same data type result = [f(row[0], ..., row[n]) for row in df[['col1', ...,'coln']].to_numpy()] # Iterating over multiple columns - differing data type result = [f(row[0], ..., row[n]) for row in zip(df['col1'], ..., df['coln'])]
비즈니스 로직을 함수로 캡슐화할 수 있다면 이를 호출하는 목록 이해를 사용할 수 있습니다. 원시 Python 코드의 단순성과 속도를 통해 임의로 복잡한 작업을 수행할 수 있습니다.
주의 사항
목록 이해는 데이터가 작업하기 쉽다고 가정합니다. 즉, 데이터 유형이 일관되고 NaN이 없지만 이것이 항상 보장되는 것은 아닙니다.
- 첫 번째 것이 더 명확하지만 NaN을 처리할 때 내장된 pandas 메서드가 있는 경우 이를 선호하거나(훨씬 더 나은 모서리 처리 논리를 가지고 있기 때문에) 비즈니스 논리에 적절한 NaN 처리 논리가 포함되어 있는지 확인하십시오.
- 혼합 데이터 유형을 다룰 때
df[['A', 'B']].to_numpy()
대신 zip(df['A'], df['B'], ...)
후자는 암시적으로 데이터를 가장 일반적인 유형으로 업캐스트합니다. 예를 들어 A가 숫자이고 B가 문자열인 경우 to_numpy()
는 전체 배열을 문자열로 캐스트합니다. 이는 원하는 것이 아닐 수 있습니다. 다행히 zip
하는 것이 이에 대한 가장 간단한 해결 방법입니다.
*마일리지는 위의 주의 사항 섹션에 설명된 이유로 인해 달라질 수 있습니다.
명백한 예
A + B
를 추가하는 간단한 예를 통해 차이점을 보여 드리겠습니다. 이것은 벡터화 가능한 연산이므로 위에서 논의한 방법의 성능을 쉽게 대조할 수 있습니다.
참조용 벤치마킹 코드 . 맨 아래 줄은 최대 성능을 짜내기 위해 NumPy와 많이 혼합되는 Pandas 스타일인 Numpandas로 작성된 함수를 측정합니다. 당신이 무엇을 하고 있는지 알지 못하는 한 numandas 코드를 작성하는 것은 피해야 합니다. 가능한 API를 vec_numpy
(즉, vec
를 선호).
그러나 항상 이렇게 잘리고 건조한 것은 아니라는 점을 언급해야 합니다. 때때로 "가장 좋은 작업 방법은 무엇입니까?"에 대한 대답은 "데이터에 따라 다릅니다"입니다. 내 조언은 하나에 정착하기 전에 데이터에 대한 다양한 접근 방식을 테스트하는 것입니다.
추가 읽기
* Pandas 문자열 메서드는 시리즈에 지정되지만 각 요소에서 작동한다는 의미에서 "벡터화"됩니다. 문자열 연산은 본질적으로 벡터화하기 어렵기 때문에 기본 메커니즘은 여전히 반복적입니다.
내가 이 답변을 쓴 이유
내가 새 사용자에게서 발견한 일반적인 경향은 "X를 수행하기 위해 내 df를 어떻게 반복할 수 있습니까?" 형식의 질문을 하는 것입니다. for
루프 내에서 작업을 수행하는 동안 iterrows()
를 호출하는 코드를 표시합니다. 여기 이유가 있습니다. 벡터화 개념을 접하지 않은 라이브러리의 새로운 사용자는 문제를 해결하는 코드를 무언가를 수행하기 위해 데이터를 반복하는 것으로 상상할 것입니다. DataFrame을 반복하는 방법을 모르기 때문에 그들이 가장 먼저 하는 일은 Google에서 이 질문을 하고 여기까지 오는 것입니다. 그런 다음 그들은 방법을 알려주는 허용된 답변을 보고 눈을 감고 반복이 올바른 일이 아닌지 먼저 묻지 않고 이 코드를 실행합니다.
이 답변의 목적은 새로운 사용자가 반복이 반드시 모든 문제에 대한 해결책은 아니며 더 좋고 빠르고 관용적인 솔루션이 존재할 수 있으며 이를 탐색하는 데 시간을 투자할 가치가 있음을 이해하도록 돕는 것입니다. 나는 반복과 벡터화의 전쟁을 시작하려는 것이 아니지만 이 라이브러리의 문제에 대한 솔루션을 개발할 때 새로운 사용자가 정보를 얻을 수 있기를 바랍니다.
cs95먼저 DataFrame의 행에 대해 실제로 반복 해야 하는지 여부를 고려하십시오. 대안 은 이 답변 을 참조하십시오.
여전히 행을 반복해야 하는 경우 아래 방법을 사용할 수 있습니다. 다른 답변에서 언급되지 않은 몇 가지 중요한 주의 사항에 유의하십시오.
itertuples()
는 iterrows()
그러나 문서(현재 pandas 0.24.2)에 따르면 주의하십시오.
iterrows: dtype
이 행에서 행으로 일치하지 않을 수 있습니다.
iterrows는 각 행에 대해 Series를 반환하기 때문에 행 전체에서 dtype을 유지하지 않습니다 (dtype은 DataFrame의 열 전체에서 유지됨). 행을 반복하는 동안 dtypes를 유지하려면 값의 명명된 튜플을 반환하고 일반적으로 iterrows()보다 훨씬 빠른 itertuples()를 사용하는 것이 좋습니다.
iterrows: 행을 수정하지 마십시오.
반복 중인 항목을 수정 해서는 안 됩니다. 모든 경우에 작동하는 것은 아닙니다. 데이터 유형에 따라 iterator는 뷰가 아닌 복사본을 반환하고 그것에 쓰는 것은 효과가 없습니다.
대신 DataFrame.apply() 를 사용하십시오.
new_df = df.apply(lambda x: x * 2)
반복문:
열 이름은 유효하지 않은 Python 식별자이거나 반복되거나 밑줄로 시작하는 경우 위치 이름으로 바뀝니다. 많은 수의 열(>255)에서는 일반 튜플이 반환됩니다.
자세한 내용 은 반복에 대한 pandas 문서를 참조하세요.
viddik13df.iterrows()
사용해야 합니다. Series
객체를 생성해야 하기 때문에 행 단위로 반복하는 것은 특히 효율적이지 않습니다.
Wes McKinneyiterrows()
가 좋은 옵션이지만 때때로 itertuples()
가 훨씬 더 빠를 수 있습니다.
df = pd.DataFrame({'a': randn(1000), 'b': randn(1000),'N': randint(100, 1000, (1000)), 'x': 'x'}) %timeit [row.a * 2 for idx, row in df.iterrows()] # => 10 loops, best of 3: 50.3 ms per loop %timeit [row[1] * 2 for row in df.itertuples()] # => 1000 loops, best of 3: 541 µs per loop
e9tdf.apply()
를 사용하여 행을 반복하고 함수에 대한 여러 열에 액세스할 수도 있습니다.
문서: DataFrame.apply()
def valuation_formula(x, y): return x * y * 0.5 df['price'] = df.apply(lambda row: valuation_formula(row['x'], row['y']), axis=1)
cheekybastard다음과 같이 df.iloc 함수를 사용할 수 있습니다.
for i in range(0, len(df)): print df.iloc[i]['c1'], df.iloc[i]['c2']
PJay효율적으로 반복하는 방법
Pandas 데이터 프레임을 실제로 반복 해야 하는 경우 iterrows() 사용 을 피하고 싶을 것입니다. 다른 방법이 있으며 일반적인 iterrows()
가 최고가 아닙니다. itertuples()는 100배 더 빠를 수 있습니다.
간단히 말해서:
- 일반적으로
df.itertuples(name=None)
합니다. 특히 고정 수의 열과 255개 미만의 열이 있는 경우. 포인트 (3) 참조 - 그렇지 않으면 열에 공백이나 '-'와 같은 특수 문자가 있는 경우를 제외하고
df.itertuples()
포인트 (2) 참조 - 마지막 예제를 사용하면 데이터 프레임에 이상한 열이 있더라도
itertuples()
를 사용할 수 있습니다. 포인트 (4) 참조 - 이전 솔루션을 사용할 수 없는 경우에만
iterrows()
포인트 (1) 참조
Pandas 데이터 프레임의 행을 반복하는 다양한 방법:
백만 개의 행과 4개의 열이 있는 임의의 데이터 프레임을 생성합니다.
df = pd.DataFrame(np.random.randint(0, 100, size=(1000000, 4)), columns=list('ABCD')) print(df)
1) 일반적인 iterrows()
는 편리하지만 느립니다.
start_time = time.clock() result = 0 for _, row in df.iterrows(): result += max(row['B'], row['C']) total_elapsed_time = round(time.clock() - start_time, 2) print("1. Iterrows done in {} seconds, result = {}".format(total_elapsed_time, result))
2) 기본 itertuples()
My Col-Name is very Strange
와 같은 열 이름에서는 작동하지 않습니다(열이 반복되거나 열 이름을 단순히 변환할 수 없는 경우 이 방법을 피해야 합니다. Python 변수 이름으로).:
start_time = time.clock() result = 0 for row in df.itertuples(index=False): result += max(row.B, row.C) total_elapsed_time = round(time.clock() - start_time, 2) print("2. Named Itertuples done in {} seconds, result = {}".format(total_elapsed_time, result))
3) itertuples()
는 훨씬 빠르지만 열마다 변수를 정의해야 하므로 실제로 편리하지 않습니다.
start_time = time.clock() result = 0 for(_, col1, col2, col3, col4) in df.itertuples(name=None): result += max(col2, col3) total_elapsed_time = round(time.clock() - start_time, 2) print("3. Itertuples done in {} seconds, result = {}".format(total_elapsed_time, result))
4) 마지막으로 itertuples()
라는 이름은 이전 지점보다 느리지만 열마다 변수를 정의할 필요가 없으며 My Col-Name is very Strange
와 같은 열 이름과 함께 작동합니다.
start_time = time.clock() result = 0 for row in df.itertuples(index=False): result += max(row[df.columns.get_loc('B')], row[df.columns.get_loc('C')]) total_elapsed_time = round(time.clock() - start_time, 2) print("4. Polyvalent Itertuples working even with special characters in the column name done in {} seconds, result = {}".format(total_elapsed_time, result))
산출:
ABCD 0 41 63 42 23 1 54 9 24 65 2 15 34 10 9 3 39 94 82 97 4 4 88 79 54 ... .. .. .. .. 999995 48 27 4 25 999996 16 51 34 28 999997 1 39 61 14 999998 66 51 27 70 999999 51 53 47 99 [1000000 rows x 4 columns] 1. Iterrows done in 104.96 seconds, result = 66151519 2. Named Itertuples done in 1.26 seconds, result = 66151519 3. Itertuples done in 0.94 seconds, result = 66151519 4. Polyvalent Itertuples working even with special characters in the column name done in 2.94 seconds, result = 66151519
이 기사는 iterrows와 itertuples 간의 매우 흥미로운 비교입니다.
Romain Capron행과 열 을 반복하는 방법을 찾고 있었고 여기에서 끝났습니다.
for i, row in df.iterrows(): for j, column in row.iteritems(): print(column)
Lucas Bnamedtuple
을 구현하는 고유한 반복자를 작성할 수 있습니다.
from collections import namedtuple def myiter(d, cols=None): if cols is None: v = d.values.tolist() cols = d.columns.values.tolist() else: j = [d.columns.get_loc(c) for c in cols] v = d.values[:, j].tolist() n = namedtuple('MyTuple', cols) for line in iter(v): yield n(*line)
pd.DataFrame.itertuples
와 직접 비교할 수 있습니다. 동일한 작업을 더 효율적으로 수행하는 것을 목표로 하고 있습니다.
내 기능이있는 주어진 데이터 프레임의 경우 :
list(myiter(df)) [MyTuple(c1=10, c2=100), MyTuple(c1=11, c2=110), MyTuple(c1=12, c2=120)]
또는 pd.DataFrame.itertuples
:
list(df.itertuples(index=False)) [Pandas(c1=10, c2=100), Pandas(c1=11, c2=110), Pandas(c1=12, c2=120)]
종합적인 테스트
우리는 모든 열을 사용 가능하게 만들고 열의 부분 집합을 테스트합니다.
def iterfullA(d): return list(myiter(d)) def iterfullB(d): return list(d.itertuples(index=False)) def itersubA(d): return list(myiter(d, ['col3', 'col4', 'col5', 'col6', 'col7'])) def itersubB(d): return list(d[['col3', 'col4', 'col5', 'col6', 'col7']].itertuples(index=False)) res = pd.DataFrame( index=[10, 30, 100, 300, 1000, 3000, 10000, 30000], columns='iterfullA iterfullB itersubA itersubB'.split(), dtype=float ) for i in res.index: d = pd.DataFrame(np.random.randint(10, size=(i, 10))).add_prefix('col') for j in res.columns: stmt = '{}(d)'.format(j) setp = 'from __main__ import d, {}'.format(j) res.at[i, j] = timeit(stmt, setp, number=100) res.groupby(res.columns.str[4:-1], axis=1).plot(loglog=True);
piRSquareddataframe
모든 행을 반복하려면 다음을 사용할 수 있습니다.
for x in range(len(date_example.index)): print date_example['Date'].iloc[x]
Pedro Lobito for ind in df.index: print df['c1'][ind], df['c2'][ind]
Grag2015때때로 유용한 패턴은 다음과 같습니다.
# Borrowing @KutalmisB df example df = pd.DataFrame({'col1': [1, 2], 'col2': [0.1, 0.2]}, index=['a', 'b']) # The to_dict call results in a list of dicts # where each row_dict is a dictionary with k:v pairs of columns:value for that row for row_dict in df.to_dict(orient='records'): print(row_dict)
결과:
{'col1':1.0, 'col2':0.1} {'col1':2.0, 'col2':0.2}
Zach요컨대
- 가능하면 벡터화 사용
- 작업을 벡터화할 수 없는 경우 - 목록 이해를 사용하십시오.
- 전체 행을 나타내는 단일 객체가 필요한 경우 - itertuple을 사용하십시오.
- 위의 내용이 너무 느린 경우 - swifter.apply를 시도하십시오.
- 여전히 너무 느린 경우 - Cython 루틴을 시도하십시오.
기준
artoby업데이트 : cs95는 일반 numpy 벡터화를 포함하도록 답변을 업데이트했습니다. 당신은 단순히 그의 대답을 참조할 수 있습니다.
cs95는 Pandas 벡터화가 데이터 프레임으로 물건을 계산하는 다른 Pandas 방법보다 훨씬 뛰어나다는 것을 보여줍니다.
먼저 데이터 프레임을 NumPy 배열로 변환한 다음 벡터화를 사용하면 Pandas 데이터 프레임 벡터화보다 훨씬 빠르고 데이터 프레임 시리즈로 다시 전환하는 시간도 포함된다는 점을 추가하고 싶었습니다.
cs95의 벤치마크 코드에 다음 함수를 추가하면 매우 명확해집니다.
def np_vectorization(df): np_arr = df.to_numpy() return pd.Series(np_arr[:,0] + np_arr[:,1], index=df.index) def just_np_vectorization(df): np_arr = df.to_numpy() return np_arr[:,0] + np_arr[:,1]
bug_sprayA의 모든 행 루프에 dataframe
편리하게 각 행의 사용 가치, namedtuples
변환 할 수 있습니다 ndarray
의. 예를 들어:
df = pd.DataFrame({'col1': [1, 2], 'col2': [0.1, 0.2]}, index=['a', 'b'])
행 반복:
for row in df.itertuples(index=False, name='Pandas'): print np.asarray(row)
결과:
[ 1. 0.1] [ 2. 0.2]
index=True
이면 인덱스가 튜플의 첫 번째 요소로 추가되며 일부 응용 프로그램에서는 바람직하지 않을 수 있습니다.
Herpes Free EngineerSeries가 아닌 DataFrame을 반환하는 동안 throw 행을 반복하는 방법이 있습니다. DataFrame으로 반환될 행에 대한 목록으로 index를 전달할 수 있다고 언급한 사람은 아무도 없습니다.
for i in range(len(df)): row = df.iloc[[i]]
이중 대괄호의 사용에 유의하십시오. 단일 행이 있는 DataFrame을 반환합니다.
Zeitgeist값을 보고 수정하려면 iterrows()
합니다. for 루프에서 튜플 풀기(예: i, row
)를 사용하여 값을 보기 위해 row
을 사용하고 값을 수정하려는 경우 loc
메서드와 함께 i
이전 답변에서 언급했듯이 여기에서 반복 중인 항목을 수정하면 안 됩니다.
for i, row in df.iterrows(): df_column_A = df.loc[i, 'A'] if df_column_A == 'Old_Value': df_column_A = 'New_value'
여기서 row
은 해당 행의 복사본이지 뷰가 아닙니다. row['A'] = 'New_Value'
와 같이 작성해서는 안 되며 DataFrame을 수정하지 않습니다. 그러나 i
및 loc
을 사용하고 DataFrame을 지정하여 작업을 수행할 수 있습니다.
HosseinPandas 데이터 프레임의 행을 반복하는 방법에는 여러 가지가 있습니다. 매우 간단하고 직관적인 방법은 다음과 같습니다.
df = pd.DataFrame({'A':[1, 2, 3], 'B':[4, 5, 6], 'C':[7, 8, 9]}) print(df) for i in range(df.shape[0]): # For printing the second column print(df.iloc[i, 1]) # For printing more than one columns print(df.iloc[i, [0, 2]])
shubham ranjan가장 쉬운 방법은 apply
기능을 사용하는 것입니다.
def print_row(row): print row['c1'], row['c2'] df.apply(lambda row: print_row(row), axis=1)
François B.더 빠른 속도 향상을 위해 NumPy 인덱싱을 수행할 수도 있습니다. 실제로 반복하지는 않지만 특정 응용 프로그램의 경우 반복보다 훨씬 잘 작동합니다.
subset = row['c1'][0:5] all = row['c1'][:]
배열로 캐스팅할 수도 있습니다. 이러한 인덱스/선택 항목은 이미 NumPy 배열처럼 작동해야 하지만 문제가 발생하여 캐스트해야 했습니다.
np.asarray(all) imgs[:] = cv2.resize(imgs[:], (224,224) ) # Resize every image in an hdf5 file
James L.이 예에서는 iloc을 사용하여 데이터 프레임의 각 숫자를 분리합니다.
import pandas as pd a = [1, 2, 3, 4] b = [5, 6, 7, 8] mjr = pd.DataFrame({'a':a, 'b':b}) size = mjr.shape for i in range(size[0]): for j in range(size[1]): print(mjr.iloc[i, j])
mjr2000일부 라이브러리(예: 내가 사용하는 Java interop 라이브러리)는 데이터를 스트리밍하는 경우와 같이 한 번에 한 행씩 값을 전달해야 합니다. 스트리밍 특성을 복제하기 위해 데이터 프레임 값을 하나씩 '스트리밍'합니다. 아래에 작성했는데 때때로 유용합니다.
class DataFrameReader: def __init__(self, df): self._df = df self._row = None self._columns = df.columns.tolist() self.reset() self.row_index = 0 def __getattr__(self, key): return self.__getitem__(key) def read(self) -> bool: self._row = next(self._iterator, None) self.row_index += 1 return self._row is not None def columns(self): return self._columns def reset(self) -> None: self._iterator = self._df.itertuples() def get_index(self): return self._row[0] def index(self): return self._row[0] def to_dict(self, columns: List[str] = None): return self.row(columns=columns) def tolist(self, cols) -> List[object]: return [self.__getitem__(c) for c in cols] def row(self, columns: List[str] = None) -> Dict[str, object]: cols = set(self._columns if columns is None else columns) return {c : self.__getitem__(c) for c in self._columns if c in cols} def __getitem__(self, key) -> object: # the df index of the row is at index 0 try: if type(key) is list: ix = [self._columns.index(key) + 1 for k in key] else: ix = self._columns.index(key) + 1 return self._row[ix] except BaseException as e: return None def __next__(self) -> 'DataFrameReader': if self.read(): return self else: raise StopIteration def __iter__(self) -> 'DataFrameReader': return self
사용할 수 있는 항목:
for row in DataFrameReader(df): print(row.my_column_name) print(row.to_dict()) print(row['my_column_name']) print(row.tolist())
그리고 반복되는 행에 대한 값/이름 매핑을 유지합니다. 분명히 위에 표시된 대로 적용 및 Cython을 사용하는 것보다 훨씬 느리지만 일부 상황에서는 필요합니다.
morganics여기에 있는 많은 답변이 정확하고 명확하게 지적하듯이 일반적으로 Pandas에서 루프를 시도하지 말고 벡터화된 코드를 작성해야 합니다. 하지만 문제가 남아 혹시 팬더에서 루프를 작성하고, 가장 좋은 방법 그렇다면 이러한 상황에서 루프해야합니다.
루프가 적절한 일반적인 상황이 적어도 하나는 있다고 생각합니다. 다른 행의 값에 의존하는 일부 함수를 다소 복잡한 방식으로 계산해야 할 때입니다. 이 경우 루핑 코드는 벡터화된 코드보다 더 간단하고 읽기 쉬우며 오류 발생 가능성이 적습니다. 루핑 코드도 더 빠를 수 있습니다.
나는 이것을 예를 들어 보여주려고 노력할 것이다. 열의 누적 합계를 구하지만 다른 열이 0과 같을 때마다 재설정한다고 가정합니다.
import pandas as pd import numpy as np df = pd.DataFrame( { 'x':[1,2,3,4,5,6], 'y':[1,1,1,0,1,1] } ) # xy desired_result #0 1 1 1 #1 2 1 3 #2 3 1 6 #3 4 0 4 #4 5 1 9 #5 6 1 15
이것은 특히 읽기 어려운 것은 아니지만, 특히 이미 Pandas에 대한 경험이 많지 않은 경우에는 이를 달성하기 위해 한 줄의 Pandas를 확실히 작성할 수 있는 좋은 예입니다.
df.groupby( (df.y==0).cumsum() )['x'].cumsum()
groupby
를 피하여 더 빠른 코드를 작성할 수도 있지만 대부분의 상황에서 충분히 빠르지만 가독성이 훨씬 떨어집니다.
또는 이것을 루프로 작성하면 어떻게 될까요? NumPy를 사용하여 다음과 같은 작업을 수행할 수 있습니다.
import numba as nb @nb.jit(nopython=True) # Optional def custom_sum(x,y): x_sum = x.copy() for i in range(1,len(df)): if y[i] > 0: x_sum[i] = x_sum[i-1] + x[i] return x_sum df['desired_result'] = custom_sum( df.x.to_numpy(), df.y.to_numpy() )
물론 DataFrame 열을 NumPy 배열로 변환하는 데 약간의 오버헤드가 필요하지만 핵심 코드는 Pandas 또는 NumPy에 대해 전혀 알지 못하더라도 읽을 수 있는 한 줄의 코드에 불과합니다.
if y[i] > 0: x_sum[i] = x_sum[i-1] + x[i]
그리고 이 코드는 실제로 벡터화된 코드보다 빠릅니다. 100,000개의 행이 있는 일부 빠른 테스트에서 위의 방법은 groupby 접근 방식보다 약 10배 빠릅니다. 속도에 대한 한 가지 핵심은 선택 사항인 마비입니다. "@nb.jit" 줄이 없으면 루핑 코드는 실제로 groupby 접근 방식보다 약 10배 느립니다.
분명히 이 예제는 관련 오버헤드가 있는 루프를 작성하는 것보다 한 줄의 팬더를 선호할 만큼 간단합니다. 그러나 NumPy/numba 루프 접근 방식의 가독성이나 속도가 합리적일 수 있는 이 문제의 더 복잡한 버전이 있습니다.
JohnE이 게시물의 훌륭한 답변과 함께 Divide and Conquer 접근 방식을 제안할 예정입니다. 다른 훌륭한 답변을 폐지하기 위해 이 답변을 작성하는 것이 아니라 효율적으로 작동하는 다른 접근 방식으로 이를 수행하기 위해 이 답변을 작성하는 것입니다. 팬더 데이터 프레임 splitting
하고 merging
하는 두 단계가 있습니다.
분할 정복의 장점:
- 데이터 프레임 유형을 다른 유형으로 캐스팅하기 위해 벡터화 또는 다른 방법을 사용할 필요가 없습니다.
- 일반적으로 추가 시간이 소요되는 코드를 Cythonize할 필요가 없습니다.
-
iterrows()
와 itertuples()
모두 전체 데이터 프레임에서 동일한 성능을 보였습니다. -
index
선택에 따라 반복을 기하급수적으로 가속화할 수 있습니다. index
높을수록 반복 프로세스가 빨라집니다.
분할 및 정복의 단점:
- 동일한 데이터 프레임 및 다른 슬라이스에 대한 반복 프로세스에 대한 종속성이 없어야 합니다. 즉, 다른 슬라이스 에서 읽거나 쓰고 싶다면 그렇게 하기 어려울 수 있습니다.
=================== 분할 정복 방식 =================
1단계: 분할/슬라이스
이 단계에서는 전체 데이터 프레임에 대해 반복을 나눕니다. csv 파일을 pandas df로 읽은 다음 반복한다고 생각하십시오. 5,000,000개의 레코드가 있는 경우를 대비하여 100,000개의 레코드로 분할할 것입니다.
참고: 이 페이지의 다른 솔루션에서 설명된 다른 런타임 분석과 같이 반복해야 합니다. "레코드 수"는 df에서 검색할 때 "런타임"의 기하급수적인 비율을 갖습니다. 내 데이터에 대한 벤치마크를 기반으로 한 결과는 다음과 같습니다.
Number of records | Iteration per second ======================================== 100,000 | 500 it/s 500,000 | 200 it/s 1,000,000 | 50 it/s 5,000,000 | 20 it/s
2단계: 병합
이것은 쉬운 단계가 될 것입니다. 작성된 모든 csv 파일을 하나의 데이터 프레임으로 병합하고 더 큰 csv 파일에 씁니다.
샘플 코드는 다음과 같습니다.
# Step 1 (Splitting/Slicing) import pandas as pd df_all = pd.read_csv('C:/KtV.csv') df_index = 100000 df_len = len(df) for i in range(df_len // df_index + 1): lower_bound = i * df_index higher_bound = min(lower_bound + df_index, df_len) # splitting/slicing df (make sure to copy() otherwise it will be a view df = df_all[lower_bound:higher_bound].copy() ''' write your iteration over the sliced df here using iterrows() or intertuples() or ... ''' # writing into csv files df.to_csv('C:/KtV_prep_'+str(i)+'.csv') # Step 2 (Merging) filename='C:/KtV_prep_' df = (pd.read_csv(f) for f in [filename+str(i)+'.csv' for i in range(ktv_len // ktv_index + 1)]) df_prep_all = pd.concat(df) df_prep_all.to_csv('C:/KtV_prep_all.csv')
참조:
dataframe에 대한 효율적인 반복 방법
csv 파일을 하나의 Pandas Dataframe으로 연결
imanzabetdf.iterrows()는 a가 인덱스이고 b가 행인 튜플(a,b)을 반환합니다.
Ashvani Jaiswaldf.iloc[]
사용하십시오. 예를 들어 데이터 프레임 'rows_df' 사용:
또는
특정 행에서 값을 가져오려면 데이터 프레임을 ndarray로 변환할 수 있습니다.
그런 다음 다음과 같이 행 및 열 값을 선택합니다.
dna-data내 2센트만 더하면,
허용된 답변에서 알 수 있듯이 행에 함수를 적용하는 가장 빠른 방법은 벡터화된 함수 , 소위 numpy ufuncs
(범용 함수)를 사용하는 것입니다.
numpy
아직 구현되지 않은 경우 어떻게 해야 합니까?
numba
vectorize
데코레이터를 사용하면 다음과 같이 Python에서 직접 ufunc를 쉽게 만들 수 있습니다.
from numba import vectorize, float64 @vectorize([float64(float64)]) def f(x): #x is your line, do something with it, and return a float
이 기능에 대한 문서는 다음과 같습니다. https://numba.pydata.org/numba-doc/latest/user/vectorize.html
Nephanth아마도 가장 우아한 솔루션일 것입니다(그러나 확실히 가장 효율적이지는 않음).
for row in df.values: c2 = row[1] print(row) # ... for c1, c2 in df.values: # ...
참고:
- 문서는 대신
.to_numpy()
를 사용할 것을 명시적으로 권장합니다. -
object
의 모든 열에 맞는 dtype을 갖습니다. - 처음부터 루프를 사용하지 않는 좋은 이유가 있습니다
그래도 저는 이 옵션이 여기에 포함되어야 하며, (생각해야 할) 사소한 문제에 대한 직접적인 솔루션으로 포함되어야 한다고 생각합니다.
Ernesto Elsäßer더 나은 방법은 zip을 사용하여 키 값 쌍을 만든 다음 키로 행 값에 액세스하여 데이터 프레임을 사전으로 변환하는 것입니다.
inp = [{'c1':10, 'c2':100}, {'c1':11,'c2':110}, {'c1':12,'c2':120}] df = pd.DataFrame(inp) print(df) for row in inp: for (k,v) in zip(row.keys(), row.values()): print(k,v)
산출:
c1 10 c2 100 c1 11 c2 110 c1 12 c2 120
Golden Lion출처 : http:www.stackoverflow.com/questions/16476924/how-to-iterate-over-rows-in-a-dataframe-in-pandas