테이블 형식 데이터와 함께 Pandas를 사용해 본 적이 있다면 데이터를 가져와서 정리하고 변환한 다음 모델에 대한 입력으로 사용하는 프로세스에 익숙할 것입니다. 그러나 코드를 확장하고 프로덕션에 적용해야 하는 경우 Pandas 파이프라인이 충돌하기 시작하고 느리게 실행될 가능성이 높습니다. 이 글에서는 Pandas 코드 실행 속도를 높이고 데이터 처리 효율성을 향상하며 일반적인 함정을 피하는 데 도움이 되는 2가지 팁을 공유하겠습니다.
Pandas에서 벡터화 작업은 행별로 반복할 필요 없이 전체 데이터 프레임의 열을 보다 간결한 방식으로 처리할 수 있는 효율적인 도구입니다.
방송은 벡터화된 조작의 핵심 요소로, 다양한 모양의 개체를 직관적으로 조작할 수 있게 해줍니다.
eg1: 요소가 3개인 배열 a에 스칼라 b를 곱하면 Source와 동일한 모양의 배열이 생성됩니다.
eg2: 덧셈 연산을 수행할 때 모양이 (4,1)인 배열 a와 모양 (3,)이 있는 배열 b를 추가하면 결과는 모양이 (4,3)인 배열이 됩니다.
이를 논의하는 기사가 많이 있었는데, 특히 대규모 행렬 곱셈이 일반적인 딥 러닝에서 그렇습니다. 이 기사에서는 두 가지 간단한 예를 설명합니다.
먼저, 주어진 정수가 열에 나타나는 횟수를 세고 싶다고 가정해 보겠습니다. 가능한 방법은 2가지입니다.
"""计算DataFrame X 中 "column_1" 列中等于目标值 target 的元素个数。参数:X: DataFrame,包含要计算的列 "column_1"。target: int,目标值。返回值:int,等于目标值 target 的元素个数。"""# 使用循环计数def count_loop(X, target: int) -> int:return sum(x == target for x in X["column_1"])# 使用矢量化操作计数def count_vectorized(X, target: int) -> int:return (X["column_1"] == target).sum()
이제 날짜 열이 있는 DataFrame이 있고 이를 지정된 일 수만큼 오프셋하려고 한다고 가정합니다. 벡터화된 연산을 사용한 계산은 다음과 같습니다.
def offset_loop(X, days: int) -> pd.DataFrame:d = pd.Timedelta(days=days)X["column_const"] = [x + d for x in X["column_10"]]return Xdef offset_vectorized(X, days: int) -> pd.DataFrame:X["column_const"] = X["column_10"] + pd.Timedelta(days=days)return X
반복하는 첫 번째이자 가장 직관적인 방법은 Python for 루프를 사용하는 것입니다.
def loop(df: pd.DataFrame, remove_col: str, words_to_remove_col: str) -> list[str]:res = []i_remove_col = df.columns.get_loc(remove_col)i_words_to_remove_col = df.columns.get_loc(words_to_remove_col)for i_row in range(df.shape[0]):res.append(remove_words(df.iat[i_row, i_remove_col], df.iat[i_row, i_words_to_remove_col]))return result
def apply(df: pd.DataFrame, remove_col: str, words_to_remove_col: str) -> list[str]:return df.apply(func=lambda x: remove_words(x[remove_col], x[words_to_remove_col]), axis=1).tolist()
df.apply를 반복할 때마다 제공된 호출 가능 함수는 인덱스가 df.columns이고 값이 행인 시리즈를 가져옵니다. 이는 팬더가 모든 루프에서 시퀀스를 생성해야 함을 의미하며 이는 비용이 많이 듭니다. 비용을 줄이려면 다음과 같이 사용할 df의 하위 집합에 대해 Apply를 호출하는 것이 좋습니다.
def apply_only_used_cols(df: pd.DataFrame, remove_col: str, words_to_remove_col: str) -> list[str]:return df[[remove_col, words_to_remove_col]].apply(func=lambda x: remove_words(x[remove_col], x[words_to_remove_col]), axis=1)
목록과 결합된 반복자를 사용하여 반복하는 것이 확실히 더 좋습니다. itertuples는 행 데이터로 (명명된) 튜플을 생성합니다.
def itertuples_only_used_cols(df: pd.DataFrame, remove_col: str, words_to_remove_col: str) -> list[str]:return [remove_words(x[0], x[1])for x in df[[remove_col, words_to_remove_col]].itertuples(index=False, name=None)]
zip은 반복 가능한 객체를 허용하고 튜플을 생성합니다. 여기서 i 번째 튜플은 주어진 반복 가능한 객체의 모든 i 번째 요소를 순서대로 포함합니다.
def zip_only_used_cols(df: pd.DataFrame, remove_col: str, words_to_remove_col: str) -> list[str]:return [remove_words(x, y) for x, y in zip(df[remove_col], df[words_to_remove_col])]
def to_dict_only_used_columns(df: pd.DataFrame) -> list[str]:return [remove_words(row[remove_col], row[words_to_remove_col])for row in df[[remove_col, words_to_remove_col]].to_dict(orient="records")]
우리가 논의한 반복 기술 외에도 캐싱과 병렬화라는 두 가지 다른 방법이 코드 성능을 향상시키는 데 도움이 될 수 있습니다. 캐싱은 동일한 매개변수를 사용하여 pandas 함수를 여러 번 호출하는 경우 특히 유용합니다. 예를 들어 중복 값이 많은 데이터세트에 Remove_words를 적용한 경우 functools.lru_cache를 사용하면 함수 결과를 저장하고 매번 다시 계산하지 않아도 됩니다. lru_cache를 사용하려면 간단히 @lru_cache 데코레이터를 Remove_words 선언에 추가한 다음 선호하는 반복 방법을 사용하여 데이터세트에 함수를 적용하세요. 이렇게 하면 코드의 속도와 효율성이 크게 향상될 수 있습니다. 다음 코드를 예로 들어 보겠습니다.
@lru_cachedef remove_words(...):... # Same implementation as beforedef zip_only_used_cols_cached(df: pd.DataFrame, remove_col: str, words_to_remove_col: str) -> list[str]:return [remove_words(x, y) for x, y in zip(df[remove_col], df[words_to_remove_col])]
이 데코레이터를 추가하면 이전에 발생한 입력의 출력을 "기억"하는 함수가 생성되므로 모든 코드를 다시 실행할 필요가 없습니다.
마지막 비장의 카드는 pandaralllel을 사용하여 여러 개의 독립적인 df 블록에 걸쳐 함수 호출을 병렬화하는 것입니다. 이 도구는 사용하기 쉽습니다. 도구를 가져와서 초기화한 다음 모든 .applys를 .parallel_applys로 변경하면 됩니다.
아아아아위 내용은 Pandas 코드의 효율성을 향상시키는 두 가지 유용한 팁의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!