source

단일 컬럼에 대해 apply() 함수를 사용하려면 어떻게 해야 합니까?

factcode 2023. 1. 15. 17:14
반응형

단일 컬럼에 대해 apply() 함수를 사용하려면 어떻게 해야 합니까?

두 개의 열이 있는 판다 데이터 프레임이 있습니다.두 번째 열에 영향을 주지 않고 첫 번째 열의 값을 변경하고 첫 번째 열의 값만 변경해도 데이터 프레임 전체를 되돌려야 합니다.팬더에 적용해서 어떻게 하면 되나요?

프레임 「」이 지정됩니다.df같이요.

   a  b
0  1  2
1  2  3
2  3  4
3  4  5

원하는 것은 다음과 같습니다.

df['a'] = df['a'].apply(lambda x: x + 1)

이 값은 다음과 같습니다.

   a  b
0  2  2
1  3  3
2  4  4
3  5  5

단일 컬럼을 사용하는 것이 좋습니다.map() 이렇게요.

df = pd.DataFrame([{'a': 15, 'b': 15, 'c': 5}, {'a': 20, 'b': 10, 'c': 7}, {'a': 25, 'b': 30, 'c': 9}])

    a   b  c
0  15  15  5
1  20  10  7
2  25  30  9



df['a'] = df['a'].map(lambda a: a / 2.)

      a   b  c
0   7.5  15  5
1  10.0  10  7
2  12.5  30  9

프레임 지정df ★★★★★★complex_function ,

  import pandas as pd

  def complex_function(x, y=0):
      if x > 5 and x > y:
          return 1
      else:
          return 2

  df = pd.DataFrame(data={'col1': [1, 4, 6, 2, 7], 'col2': [6, 7, 1, 2, 8]})
     col1  col2
  0     1     6
  1     4     7
  2     6     1
  3     2     2
  4     7     8

하나의 컬럼에서만 apply()를 사용할 수 있는 솔루션이 여러 개 있습니다.다음에 자세히 설명하겠습니다.

I. 심플한 솔루션

간단한 해결책은 @Fabio Lamanna의 것입니다.

  df['col1'] = df['col1'].apply(complex_function)

출력:

     col1  col2
  0     2     6
  1     2     7
  2     1     1
  3     2     2
  4     1     8

첫 번째 열만 수정되고 두 번째 열은 변경되지 않습니다.해결책은 아름답다.코드 한 줄에 불과하며 "col1을 가져와서 complex_function을 적용하세요."라고 거의 영어로 쓰여져 있습니다.

그러나 다른 열(예: 'col2')의 데이터가 필요한 경우에는 작동하지 않습니다. 'col2'에 'ycomplex_function뭔가 다른게 필요할거야

II. 데이터 프레임 전체를 사용한 솔루션

또는 다음 SO 게시물에 설명대로 데이터 프레임 전체를 사용할 수도 있습니다.

  df['col1'] = df.apply(lambda x: complex_function(x['col1']), axis=1)

또는 (나처럼) 람다 함수가 없는 솔루션을 선호하는 경우:

  def apply_complex_function(x): return complex_function(x['col1'])
  df['col1'] = df.apply(apply_complex_function, axis=1) 

이 솔루션에는 설명할 필요가 있는 것이 많이 있습니다.apply() 함수는 pd로 동작합니다.시리즈와 PD.데이터 프레임그러나 사용할 수 없습니다.df['col1'] = df.apply(complex_function).loc[:, 'col1']왜냐하면, 그것은 그것을 던질 것이기 때문이다.ValueError.

따라서 사용할 열을 지정해야 합니다.복잡한 것은 apply() 함수는 콜러블만 받아들입니다.이 문제를 해결하려면 다음 열로 (람바다) 함수를 정의해야 합니다.x['col1']인수로 지정합니다. 즉, 열 정보를 다른 함수로 래핑합니다.

축 입니다(「0」).axis=0즉, 행이 아닌 열 단위로 실행을 시도합니다.첫 번째 솔루션에서는 문제가 되지 않았습니다.apply()에게 pd를 부여했기 때문입니다. 입력이 . 하지만 이제 입력은 데이터 프레임이므로 명시적이어야 합니다.axis=1(얼마나 자주 잊어버리는지 궁금하네요.

람다 함수가 있는 버전을 선호하는지 여부는 주관적입니다.내 생각에 코드 줄은 람다 함수를 넣지 않아도 읽을 수 있을 정도로 복잡하다.(lambda) 기능은 래퍼로서만 필요합니다.그냥 보일러 코드예요.독자는 그것에 신경 쓰지 말아야 한다.

이제 두 번째 열을 고려하도록 이 솔루션을 쉽게 수정할 수 있습니다.

    def apply_complex_function(x): return complex_function(x['col1'], x['col2'])
    df['col1'] = df.apply(apply_complex_function, axis=1)

출력:

     col1  col2
  0     2     6
  1     2     7
  2     1     1
  3     2     2
  4     2     8

에서는 첫 조건인 '4'에서 '1'에서 '2되었습니다.첫 번째 조건이7 > 5이지만 두 조건 " " " " " " 。7 > 8짓입니니다다

코드의 첫 번째 행(즉, 함수)만 변경하면 되고 두 번째 행은 변경할 필요가 없습니다.


사이드 노트

정보를 함수에 넣지 마십시오.

  def bad_idea(x):
      return x['col1'] ** 2

이렇게 하면 열 이름에 따라 일반적인 함수를 만들 수 있습니다!다음 번에 이 기능을 사용할 때는 사용할 수 없기 때문에 이는 잘못된 생각입니다.더 나쁜 점: 기존 기능에서 작동하도록 다른 데이터 프레임의 열 이름을 변경할 수도 있습니다. (가만히 하고 실행).미끄러운 경사면입니다!)


III. apply()를 사용하지 않는 대체 솔루션

OP에서는 특별히 apply()를 사용한 솔루션을 요구했지만 대체 솔루션이 제안되었습니다.예를 들어, @George Petrov의 답변은 map()을 사용할 것을 제안했고, @Thibaut Dubernet의 답변은 assign()을 제안했습니다.

apply()는 벡터화되지 않기 때문에 apply()가 최적의 솔루션이 될 수 없다는 에 전적으로 동의합니다.이는 pd로부터의 고비용 함수 호출과 오버헤드를 수반하는 요소별 작업입니다.시리즈.

apply()를 사용하는 이유 중 하나는 기존 함수를 사용하고 퍼포먼스가 문제가 되지 않는다는 것입니다.또는 함수가 너무 복잡해서 벡터화된 버전이 존재하지 않습니다.

apply()를 사용하는 또 다른 이유는 groupby()조합하는 것입니다.DataFrame.apply()와 GroupBy.apply()는 다른 함수입니다.

따라서 몇 가지 대안을 고려하는 것이 현명합니다.

  • map()PD에게만 통한다.시리즈. 단, dict와 pd를 사용할 수 있습니다.입력으로서 시리즈.함수와 함께 map()을 사용하는 것은 apply()를 사용하는 것과 거의 호환됩니다.적용()보다 빠를 수 있습니다.상세한 것에 대하여는, 이 SO의 투고를 참조해 주세요.
  df['col1'] = df['col1'].map(complex_function)
  • applymap()데이터 프레임과 거의 동일합니다.PD를 지원하지 않습니다.Series는 항상 데이터 프레임을 반환합니다.하지만, 더 빠를 수 있습니다.문서에는 "현재 구현에서는 applymap이 첫 번째/행에서 func를 두 번 호출하여 고속 코드 경로를 사용할 수 있는지 또는 느린 코드 경로를 사용할 수 있는지 판단합니다."라고 기재되어 있습니다.하지만 성능이 정말 중요한 경우 다른 경로를 찾아야 합니다.
  df['col1'] = df.applymap(complex_function).loc[:, 'col1']
  • assign()이치노가장 기본적인 사용 사례에서만 유사한 동작을 보입니다.에서는 동작하지 않습니다.complex_function아래 예시와 같이 apply()가 필요합니다.assign()의 주요 사용 사례는 메서드 체인입니다.이것은 원래 데이터 프레임을 변경하지 않고 데이터 프레임을 반환하기 때문입니다.
  df['col1'] = df.assign(col1=df.col1.apply(complex_function))

부록: 적용 속도를 높이는 방법

@durjoy와 같은 다른 답변에서 제안되었기 때문에 여기서만 언급합니다.리스트는 완전하지 않습니다.

  1. apply()를 사용하지 마십시오.이건 장난이 아니야.대부분의 수치 연산의 경우, 팬더에는 벡터화된 방법이 존재합니다.if/else 블록은 종종 부울 인덱스와 를 조합으로 리팩터링할 수 있습니다..loc 예시는 ★★★★★★complex_function이런 식으로 리팩터링될 수 있습니다.
  2. 시튼의 리팩터.복잡한 방정식이 있고 방정식의 매개 변수가 데이터 프레임에 있는 경우 이 방법을 사용하는 것이 좋습니다.자세한 내용은 공식 팬더 사용자 가이드를 참조하십시오.
  3. 파라미터를 사용합니다.이론적으로 NumPy 축소 함수를 적용하는 경우 pd의 오버헤드가 발생하기 때문에 apply()의 퍼포먼스가 향상됩니다.시리즈가 삭제됩니다.물론 함수는 ndarray를 받아들여야 합니다.NumPy에 기능을 리팩터링해야 합니다.이렇게 하면 성능이 크게 향상됩니다.
  4. 서드파티 패키지를 사용합니다.가장 먼저 시도해야 할 것은 Numba입니다.@durjoy가 언급한 swifter는 알 수 없습니다.다른 많은 패키지는 여기서 언급할 가치가 있을 것입니다.
  5. 시도/실패/반복합니다.위에서 설명한 바와 같이 사용 사례에 따라 map()과 applymap()이 더 빠를 수 있습니다.다른 버전의 시간을 재서 가장 빠른 버전을 선택하세요.이 접근방식은 퍼포먼스 향상이 가장 적은 가장 지루한 접근방식입니다.

기능은 전혀 필요 없습니다.열 전체를 직접 작업할 수 있습니다.

데이터 예:

>>> df = pd.DataFrame({'a': [100, 1000], 'b': [200, 2000], 'c': [300, 3000]})
>>> df

      a     b     c
0   100   200   300
1  1000  2000  3000

a:

>>> df.a = df.a / 2
>>> df

     a     b     c
0   50   200   300
1  500  2000  3000

주어진 응답은 정확하지만 초기 데이터 프레임을 수정하고 이는 항상 바람직한 것은 아닙니다(그리고 OP가 "사용" 예제를 요청함).apply이 있습니다를 들어, 「새로운 데이터 프레임을 반환하다」라고 하는 것입니다.apply고 하다.

이는 를 사용하여 가능합니다.유효한 것은 다음과 같습니다.assign설명서에 기재되어 있는 바와 같이 기존 컬럼으로 이행합니다(이러한 컬럼은 내 것입니다).

DataFrame에 새 열을 할당합니다.

새 열뿐만 아니라 모든 원래 열과 함께 새 개체를 반환합니다.다시 할당된 기존 열을 덮어씁니다.

요컨대:

In [1]: import pandas as pd

In [2]: df = pd.DataFrame([{'a': 15, 'b': 15, 'c': 5}, {'a': 20, 'b': 10, 'c': 7}, {'a': 25, 'b': 30, 'c': 9}])

In [3]: df.assign(a=lambda df: df.a / 2)
Out[3]: 
      a   b  c
0   7.5  15  5
1  10.0  10  7
2  12.5  30  9

In [4]: df
Out[4]: 
    a   b  c
0  15  15  5
1  20  10  7
2  25  30  9

함수는 수정할 열뿐만 아니라 전체 데이터 프레임으로 전달되므로 람다에서 올바른 열을 선택해야 합니다.

적용 기능의 실행 속도에 관심이 많고 작업해야 할 데이터 세트가 많은 경우 Swifter를 사용하여 보다 빠르게 실행할 수 있습니다. 다음은 Panda 데이터 프레임에서 swifter를 사용한 예입니다.

import pandas as pd
import swifter

def fnc(m):
    return m*3+4

df = pd.DataFrame({"m": [1,2,3,4,5,6], "c": [1,1,1,1,1,1], "x":[5,3,6,2,6,1]})

# apply a self created function to a single column in pandas
df["y"] = df.m.swifter.apply(fnc)

이렇게 하면 모든 CPU 코어가 결과를 계산할 수 있으므로 일반 적용 함수보다 훨씬 빠릅니다.도움이 될 것 같으면 알려주세요.

빈을 고려하면서 합니다. datetime은 null 또는 빈 공간을 고려합니다.하여 datetime을 사용하고 .apply 및 방법lambda formatdatetime을 변환하고 . »if x != '' else x늘(NULL)을 사용하다

df['Date'] = df['Date'].fillna('')
df['Date'] = df['Date'].apply(lambda x : ((datetime.datetime.strptime(str(x), '%m/%d/%Y') - datetime.timedelta(days=30*365)).strftime('%Y%m%d')) if x != '' else x)

언급URL : https://stackoverflow.com/questions/34962104/how-can-i-use-the-apply-function-for-a-single-column

반응형