그룹 객체에 변형 대 적용
다음 데이터 프레임을 고려하십시오.
A B C D
0 foo one 0.162003 0.087469
1 bar one -1.156319 -1.526272
2 foo two 0.833892 -1.666304
3 bar three -2.026673 -0.322057
4 foo two 0.411452 -0.954371
5 bar two 0.765878 -0.095968
6 foo one -0.654890 0.678091
7 foo three -1.789842 -1.130922
다음 명령이 작동합니다.
> df.groupby('A').apply(lambda x: (x['C'] - x['D']))
> df.groupby('A').apply(lambda x: (x['C'] - x['D']).mean())
그러나 다음과 같은 작업은 없습니다.
> df.groupby('A').transform(lambda x: (x['C'] - x['D']))
ValueError: could not broadcast input array from shape (5) into shape (5,3)
> df.groupby('A').transform(lambda x: (x['C'] - x['D']).mean())
TypeError: cannot concatenate a non-NDFrame object
왜? 문서의 예제transform 는 그룹 을 호출 하면 행 단위 작업 처리를 수행 할 수 있다고 제안합니다 .
# Note that the following suggests row-wise operation (x.mean is the column mean)
zscore = lambda x: (x - x.mean()) / x.std()
transformed = ts.groupby(key).transform(zscore)
다시 말해, 변환은 본질적으로 특정 유형의 적용 (집계되지 않는 적용)이라고 생각했습니다. 내가 어디 틀렸어?
참고로 아래는 위의 원래 데이터 프레임 구성입니다.
df = pd.DataFrame({'A' : ['foo', 'bar', 'foo', 'bar',
'foo', 'bar', 'foo', 'foo'],
'B' : ['one', 'one', 'two', 'three',
'two', 'two', 'one', 'three'],
'C' : randn(8), 'D' : randn(8)})
.transform작업과 비슷하게 혼동되었다고 느끼 .apply면서 몇 가지 답변을 발견했습니다. 예를 들어이 답변 은 매우 도움이되었습니다.
지금까지의 테이크 아웃 은 서로 분리되어.transform 작동 (또는 Series열) 할 것 입니다 . 이것이 의미하는 것은 마지막 두 번의 호출에서입니다.
df.groupby('A').transform(lambda x: (x['C'] - x['D']))
df.groupby('A').transform(lambda x: (x['C'] - x['D']).mean())
.transform두 열에서 값을 가져 오라고 요청 했지만 실제로는 두 열을 동시에 볼 수 없습니다. transform데이터 프레임 열을 하나씩 살펴보고 반복 된 반복되는 스칼라로 구성된 시리즈 (또는 시리즈 그룹)를 다시 반환 len(input_column)합니다.
사용해야이 스칼라이므로 .transform하게는 Series일부 감소 함수의 결과는 입력에인가 Series(한 번에 단지 하나 시리즈 / 열).
데이터 프레임에서이 예제를 고려하십시오.
zscore = lambda x: (x - x.mean()) / x.std() # Note that it does not reference anything outside of 'x' and for transform 'x' is one column.
df.groupby('A').transform(zscore)
산출 할 것이다 :
C D
0 0.989 0.128
1 -0.478 0.489
2 0.889 -0.589
3 -0.671 -1.150
4 0.034 -0.285
5 1.149 0.662
6 -1.404 -0.907
7 -0.509 1.653
한 번에 하나의 열에서만 사용하는 것과 정확히 동일합니다.
df.groupby('A')['C'].transform(zscore)
굽힐 수 있는:
0 0.989
1 -0.478
2 0.889
3 -0.671
4 0.034
5 1.149
6 -1.404
7 -0.509
참고 것을 .apply마지막 예에서 ( df.groupby('A')['C'].apply(zscore)) 정확히 같은 방식으로 작동합니다,하지만 당신은 dataframe에 그것을 사용하려고한다면 실패 할 것이다 :
df.groupby('A').apply(zscore)
오류를 준다 :
ValueError: operands could not be broadcast together with shapes (6,) (2,)
다른 .transform유용한 곳은 어디 입니까? 가장 간단한 경우는 축소 함수의 결과를 원래 데이터 프레임에 다시 할당하는 것입니다.
df['sum_C'] = df.groupby('A')['C'].transform(sum)
df.sort('A') # to clearly see the scalar ('sum') applies to the whole column of the group
굽힐 수 있는:
A B C D sum_C
1 bar one 1.998 0.593 3.973
3 bar three 1.287 -0.639 3.973
5 bar two 0.687 -1.027 3.973
4 foo two 0.205 1.274 4.373
2 foo two 0.128 0.924 4.373
6 foo one 2.113 -0.516 4.373
7 foo three 0.657 -1.179 4.373
0 foo one 1.270 0.201 4.373
와 같은 시도는 .apply줄 것이라고 NaNs에서 sum_C. 때문에 .applyA가 감소 반환 Series이 다시 방송하는 방법을 알고하지 않는 :
df.groupby('A')['C'].apply(sum)
기부:
A
bar 3.973
foo 4.373
.transform데이터를 필터링하는 데 사용되는 경우도 있습니다 .
df[df.groupby(['B'])['D'].transform(sum) < -1]
A B C D
3 bar three 1.287 -0.639
7 foo three 0.657 -1.179
이것이 좀 더 명확 해지기를 바랍니다.
두 가지 주요 차이점 사이 apply와transform
transform와 applygroupby 메소드 에는 두 가지 주요 차이점이 있습니다.
apply각 그룹의 모든 열을 사용자 정의 함수에 DataFrame 으로 암시 적으로 전달 하는 한편transform각 그룹의 각 열을 Series 로 사용자 정의 함수에 전달- 전달 된 사용자 지정 함수
apply는 스칼라 또는 Series 또는 DataFrame (또는 numpy 배열 또는 목록)을 반환 할 수 있습니다. 전달 된 사용자 정의 함수transform는 그룹과 동일한 길이의 시퀀스 (1 차원 시리즈, 배열 또는 목록)를 반환해야합니다.
따라서 transform한 번에 하나의 Series에서만 apply작동하고 전체 DataFrame에서 한 번에 작동합니다.
사용자 정의 기능 검사
apply또는에 전달 된 사용자 정의 함수에 대한 입력을 검사하는 데 도움이 될 수 있습니다 transform.
예
샘플 데이터를 만들고 그룹을 검사하여 내가 말하는 것을 볼 수 있습니다.
df = pd.DataFrame({'State':['Texas', 'Texas', 'Florida', 'Florida'],
'a':[4,5,1,3], 'b':[6,10,3,11]})
df
암시 적으로 전달 된 객체의 유형을 인쇄 한 다음 실행을 중지 할 수 있도록 오류를 발생시키는 간단한 사용자 정의 함수를 만들어 봅시다.
def inspect(x):
print(type(x))
raise
이제이 함수를 groupby apply와 transform메소드 모두에 전달하여 어떤 객체가 전달되는지 확인하십시오.
df.groupby('State').apply(inspect)
<class 'pandas.core.frame.DataFrame'>
<class 'pandas.core.frame.DataFrame'>
RuntimeError
보시다시피 DataFrame은 inspect함수 로 전달됩니다 . 왜 DataFrame 유형이 두 번 인쇄되었는지 궁금 할 것입니다. 팬더는 첫 번째 그룹을 두 번 실행합니다. 계산을 완료하는 빠른 방법이 있는지 여부를 판별하기 위해이를 수행합니다. 걱정할 필요가없는 사소한 세부 사항입니다.
자, 같은 작업을하겠습니다 transform
df.groupby('State').transform(inspect)
<class 'pandas.core.series.Series'>
<class 'pandas.core.series.Series'>
RuntimeError
완전히 다른 Pandas 객체 인 Series를 전달합니다.
따라서 transform한 번에 하나의 시리즈로만 작업 할 수 있습니다. 두 열에 동시에 작동하는 것은 불가능합니다. 따라서 사용자 정의 함수 내부 a에서 열 을 빼려고 b하면에 오류가 발생합니다 transform. 아래를보십시오 :
def subtract_two(x):
return x['a'] - x['b']
df.groupby('State').transform(subtract_two)
KeyError: ('a', 'occurred at index a')
팬더가 a존재하지 않는 Series 인덱스를 찾으려고 할 때 KeyError 가 발생합니다. apply전체 DataFrame이 있으므로이 작업을 완료 할 수 있습니다 .
df.groupby('State').apply(subtract_two)
State
Florida 2 -2
3 -8
Texas 0 -2
1 -5
dtype: int64
출력은 Series이며 원래 인덱스가 유지되므로 약간 혼란 스럽지만 모든 열에 액세스 할 수 있습니다.
전달 된 팬더 객체 표시
사용자 정의 기능 내에서 전체 팬더 객체를 표시하는 데 도움이되므로 작동중인 것을 정확하게 볼 수 있습니다. 모듈 print의 display함수 를 사용 IPython.display하여 DataFrames가 jupyter 노트북의 HTML로 멋지게 출력되도록 명령문을 사용할 수 있습니다 .
from IPython.display import display
def subtract_two(x):
display(x)
return x['a'] - x['b']
변환은 그룹과 동일한 크기의 단일 차원 시퀀스를 반환해야합니다.
다른 차이점은 transform그룹과 동일한 크기의 단일 차원 시퀀스를 반환해야 한다는 것 입니다. 이 특정 인스턴스에서 각 그룹에는 두 개의 행이 있으므로 transform두 개의 행 시퀀스를 리턴해야합니다. 그렇지 않으면 오류가 발생합니다.
def return_three(x):
return np.array([1, 2, 3])
df.groupby('State').transform(return_three)
ValueError: transform must return a scalar value for each group
오류 메시지는 실제로 문제를 설명하지 않습니다. 그룹과 동일한 길이의 시퀀스를 반환해야합니다. 따라서 이와 같은 기능이 작동합니다.
def rand_group_len(x):
return np.random.rand(len(x))
df.groupby('State').transform(rand_group_len)
a b
0 0.962070 0.151440
1 0.440956 0.782176
2 0.642218 0.483257
3 0.056047 0.238208
Returning a single scalar object also works for transform
If you return just a single scalar from your custom function, then transform will use it for each of the rows in the group:
def group_sum(x):
return x.sum()
df.groupby('State').transform(group_sum)
a b
0 9 16
1 9 16
2 4 14
3 4 14
I am going to use a very simple snippet to illustrate the difference:
test = pd.DataFrame({'id':[1,2,3,1,2,3,1,2,3], 'price':[1,2,3,2,3,1,3,1,2]})
grouping = test.groupby('id')['price']
The DataFrame looks like this:
id price
0 1 1
1 2 2
2 3 3
3 1 2
4 2 3
5 3 1
6 1 3
7 2 1
8 3 2
There are 3 customer IDs in this table, each customer made three transactions and paid 1,2,3 dollars each time.
Now, I want to find the minimum payment made by each customer. There are two ways of doing it:
Using
apply:grouping.min()
The return looks like this:
id
1 1
2 1
3 1
Name: price, dtype: int64
pandas.core.series.Series # return type
Int64Index([1, 2, 3], dtype='int64', name='id') #The returned Series' index
# lenght is 3
Using
transform:grouping.transform(min)
The return looks like this:
0 1
1 1
2 1
3 1
4 1
5 1
6 1
7 1
8 1
Name: price, dtype: int64
pandas.core.series.Series # return type
RangeIndex(start=0, stop=9, step=1) # The returned Series' index
# length is 9
Both methods return a Series object, but the length of the first one is 3 and the length of the second one is 9.
If you want to answer What is the minimum price paid by each customer, then the apply method is the more suitable one to choose.
에 대답 What is the difference between the amount paid for each transaction vs the minimum payment하려면 다음을 사용하십시오 transform.
test['minimum'] = grouping.transform(min) # ceates an extra column filled with minimum payment
test.price - test.minimum # returns the difference for each row
Apply 여기서는 Series 3 크기를 반환하기 때문에 단순히 작동하지 않지만 원본 df의 길이는 9입니다. 원본 df에 쉽게 통합 할 수 없습니다.
tmp = df.groupby(['A'])['c'].transform('mean')
처럼
tmp1 = df.groupby(['A']).agg({'c':'mean'})
tmp = df['A'].map(tmp1['c'])
또는
tmp1 = df.groupby(['A'])['c'].mean()
tmp = df['A'].map(tmp1)
참고 URL : https://stackoverflow.com/questions/27517425/apply-vs-transform-on-a-group-object
'Programing' 카테고리의 다른 글
| Angular JS 지시문에 대한 포스트 렌더 콜백이 있습니까? (0) | 2020.06.25 |
|---|---|
| Django Rest Framework를 사용하여 관련 모델 필드를 어떻게 포함합니까? (0) | 2020.06.25 |
| Django TemplateDoesNotExist? (0) | 2020.06.25 |
| JDBC와 함께 try-with-resources를 어떻게 사용해야합니까? (0) | 2020.06.25 |
| Bash를 사용하여 마지막 명령의 출력을 변수로 자동 캡처합니까? (0) | 2020.06.25 |
