단일 컬럼에 대해 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'에 'y
complex_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와 같은 다른 답변에서 제안되었기 때문에 여기서만 언급합니다.리스트는 완전하지 않습니다.
- apply()를 사용하지 마십시오.이건 장난이 아니야.대부분의 수치 연산의 경우, 팬더에는 벡터화된 방법이 존재합니다.if/else 블록은 종종 부울 인덱스와 를 조합으로 리팩터링할 수 있습니다.
.loc
예시는 ★★★★★★complex_function
이런 식으로 리팩터링될 수 있습니다. - 시튼의 리팩터.복잡한 방정식이 있고 방정식의 매개 변수가 데이터 프레임에 있는 경우 이 방법을 사용하는 것이 좋습니다.자세한 내용은 공식 팬더 사용자 가이드를 참조하십시오.
- 파라미터를 사용합니다.이론적으로 NumPy 축소 함수를 적용하는 경우 pd의 오버헤드가 발생하기 때문에 apply()의 퍼포먼스가 향상됩니다.시리즈가 삭제됩니다.물론 함수는 ndarray를 받아들여야 합니다.NumPy에 기능을 리팩터링해야 합니다.이렇게 하면 성능이 크게 향상됩니다.
- 서드파티 패키지를 사용합니다.가장 먼저 시도해야 할 것은 Numba입니다.@durjoy가 언급한 swifter는 알 수 없습니다.다른 많은 패키지는 여기서 언급할 가치가 있을 것입니다.
- 시도/실패/반복합니다.위에서 설명한 바와 같이 사용 사례에 따라 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
'source' 카테고리의 다른 글
twig: 여러 조건이 있는 경우 (0) | 2023.01.15 |
---|---|
Java 8에서의 스플리터, 수집기 및 스트림에 대해서 (0) | 2023.01.15 |
매크로가 정의되어 있지 않다면 왜 매크로만 정의합니까? (0) | 2023.01.15 |
php에서 비트마스크를 구현하려면 어떻게 해야 하나요? (0) | 2023.01.15 |
상태를 업데이트하지 않는 Vuex 변환 (0) | 2023.01.15 |