<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Pandas 피봇과 그룹 연산
피봇 테이블
피봇 테이블(pivot table)이란 데이터 열(column) 중에서 두 개를 키(key)로 사용하여 데이터를 선택하는 방법을 말한다. 
피봇 테이블을 사용하기 위해서는 키가 될 수 있는 두 개의 열(column) 혹은 필드(field)를 선택하여 이 두 열을 
행 인덱스 (row index)
열 인덱스 (column index)
로 변경해야 한다.
<img src="https
Step1:  행 인덱스와, 열 인덱스가 될 자료는 키(key)의 역할을 해야 한다. 즉, 이 값으로 데이터가 유일하게(unique) 결정되어야 한다.
Step2:  그룹 연산
그룹 연산은 피봇 테이블과 달리 키에 의해서 결정되는 데이터가 복수개가 있어도 괜찮다. 대신 연산을 통해 복수개의 그룹 데이터에 대한 대표값을 정한다. 이를 split-apply-combine 연산이라고도 한다.
split 단계
특정 Key 값에 따라 데이터 그룹을 만든다.
apply 단계
각각의 그룹에 대해 원하는 연산을 하여 대표값을 생성한다.
count(), mean(), median(), min(), max()
sum(), prod(), std(), var(), quantile()
first(), last()
combine 단계
그룹의 Key 값에 대해 원하는 연산의 결과를 Value로 지정한 dict를 생성한다.
<img src="https
Step3:  문제
Step4:  문제
Step5:  groupby 명령의 인수
groupby 명령에서  Key 인수로 입력할 수 있는 값은 다음과 같다.
열 또는 열의 리스트 
행 인덱스
사전/함수
Step6:  특별한 group 별 연산
통계
describe()
그룹을 대표하는 하나의 값을 계산
agg(), aggregate()
대표값으로 필드를 교체
transform()
그룹 전체를 변형하는 계산
apply()
TIP 데이터 예제
Step7:  그룹별 통계
Step8:  그룹별 연산
Step9:  그룹의 값을 대표값으로 대체
Step10:  그룹 자체를 대체
apply 메소드는 수치값이 아닌 Group을 출력
단순히 대표값을 계산하는 것 뿐 아니라
순서 정렬, 일부 삭제 등 그룹 내의 레코드 자체를 변형하는 것도 가능
Step11:  pivot_table
pivot 명령과 groupby 명령의 중간적 성격
pivot을 수행하지만 데이터가 유니크하게 선택되지 않으면 aggfunc 인수로 정의된 함수를 수행하여 대표값 계산
디폴트 aggfunc 은 평균 계산
<ASSISTANT_TASK:>
Python Code:
data = {
    'state': ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada'],
    'year': [2000, 2001, 2002, 2001, 2002],
    'pop': [1.5, 2.5, 3.0, 2.5, 3.5]
}
df = pd.DataFrame(data, columns=["state", "year", "pop"])
df
df.pivot("state", "year", "pop")
Explanation: Pandas 피봇과 그룹 연산
피봇 테이블
피봇 테이블(pivot table)이란 데이터 열(column) 중에서 두 개를 키(key)로 사용하여 데이터를 선택하는 방법을 말한다. 
피봇 테이블을 사용하기 위해서는 키가 될 수 있는 두 개의 열(column) 혹은 필드(field)를 선택하여 이 두 열을 
행 인덱스 (row index)
열 인덱스 (column index)
로 변경해야 한다.
<img src="https://datascienceschool.net/upfiles/f281a1a51f834b72add6abc73f9c95a0.png">
pivot 메서드를 사용하면 행 인덱스, 열 인덱스, 자료가 될 3가지의 열(column)을 지정할 수 있다.
End of explanation
df.pivot("year", "pop", "state")
df.set_index(["state", "year"])
df.set_index(["state", "year"]).unstack()
Explanation: 행 인덱스와, 열 인덱스가 될 자료는 키(key)의 역할을 해야 한다. 즉, 이 값으로 데이터가 유일하게(unique) 결정되어야 한다.
End of explanation
np.random.seed(0)
df = pd.DataFrame({'key1': ['a', 'a', 'b', 'b', 'a'],
                   'key2': ['one', 'two', 'one', 'two', 'one'],
                   'data1': np.random.randn(5),
                   'data2': np.random.randn(5)})
df
Explanation: 그룹 연산
그룹 연산은 피봇 테이블과 달리 키에 의해서 결정되는 데이터가 복수개가 있어도 괜찮다. 대신 연산을 통해 복수개의 그룹 데이터에 대한 대표값을 정한다. 이를 split-apply-combine 연산이라고도 한다.
split 단계
특정 Key 값에 따라 데이터 그룹을 만든다.
apply 단계
각각의 그룹에 대해 원하는 연산을 하여 대표값을 생성한다.
count(), mean(), median(), min(), max()
sum(), prod(), std(), var(), quantile()
first(), last()
combine 단계
그룹의 Key 값에 대해 원하는 연산의 결과를 Value로 지정한 dict를 생성한다.
<img src="https://datascienceschool.net/upfiles/5cf33c481e8041ebbf56a5af1f84d487.png" style="width:80%;">
End of explanation
df.data1.groupby(df.key1).mean()
gs = df.data1.groupby(df.key1)
gs
print("="*50)
for n, g in gs:
    print("[key]:", n)
    print("[group]:", type(g))
    print("-"*50)
    print(g)
    print("-"*50)
    print("[mean]:", g.mean())
    print("="*50)
gs.mean()
Explanation: 문제: key1 값에 따른 data1의 평균은?
End of explanation
means = df.data1.groupby([df.key1, df.key2]).mean()
means
means = df.data1.groupby([df.key1, df.key2]).mean()
means
Explanation: 문제: 복합 key (key1, key2)  값에 따른 data1의 평균은?
End of explanation
np.random.seed(0)
people = pd.DataFrame(np.random.randn(5,5),
                      columns=['a','b','c','d','e'],
                      index=['Joe','Steve','Wes','Jim','Travis'])
people.ix[2:3, ['b', 'c']] = np.nan
people
print("="*80)
for n, g in people.groupby(people.index):
    print("[key]:", n)
    print("[group]:", type(g))
    print("-"*80)
    print(g)
    print("="*80)
mapping = {'Joe': 'J', 'Jim': 'J', 'Steve': 'S', 'Wes': 'S', 'Travis': 'S'}
print("="*80)
for n, g in people.groupby(mapping):
    print("[key]:", n)
    print("[group]:", type(g))
    print("-"*80)
    print(g)
    print("="*80)
cap1 = lambda x: x[0].upper()
print("="*80)
for n, g in people.groupby(cap1):
    print("[key]:", n)
    print("[group]:", type(g))
    print("-"*80)
    print(g)
    print("="*80)
print("="*80)
for n, g in people.groupby(people.columns, axis=1):
    print("[key]:", n)
    print("[group]:", type(g))
    print("-"*80)
    print(g)
    print("="*80)
mapping = {'a': 'red', 'b': 'red', 'c': 'blue', 'd': 'blue', 'e': 'red', 'f' : 'orange'}
for n, g in people.groupby(mapping, axis=1):
    print("[key]:", n)
    print("[group]:", type(g))
    print("-"*80)
    print(g)
    print("="*80)
Explanation: groupby 명령의 인수
groupby 명령에서  Key 인수로 입력할 수 있는 값은 다음과 같다.
열 또는 열의 리스트 
행 인덱스
사전/함수: Column의 값을 사전에 매핑(mapping)하거나 함수 처리하여 나온 결괏값을 키로 인식
End of explanation
%cd /home/dockeruser/data/pydata-book-master
tips = pd.read_csv('../../pydata-book-master/ch08/tips.csv')
tips.head()
tips['tip_pct'] = tips['tip'] / tips['total_bill']
tips.tail()
tips.describe()
Explanation: 특별한 group 별 연산
통계
describe()
그룹을 대표하는 하나의 값을 계산
agg(), aggregate()
대표값으로 필드를 교체
transform()
그룹 전체를 변형하는 계산
apply()
TIP 데이터 예제
End of explanation
tips.groupby(["sex", "smoker"])[["tip", "tip_pct"]].describe()
Explanation: 그룹별 통계
End of explanation
gs = tips.groupby(["sex", "smoker"])
gs_pct = gs["tip_pct"]
gs_pct.mean()
gs_pct.agg('mean')
def peak_to_peak(arr):
    return arr.max() - arr.min()
gs_pct.agg(['mean', 'std', peak_to_peak])
gs.agg({'tip_pct': 'mean', 'total_bill': peak_to_peak})
Explanation: 그룹별 연산
End of explanation
gs.agg("mean")
tips2 = tips.copy()
tips2["tips"] = gs.transform("mean")["tip_pct"]
tips2.tail(15)
Explanation: 그룹의 값을 대표값으로 대체
End of explanation
def top(df, n=5, column='tip_pct'):
    return df.sort_values(by=column)[-n:]
top(tips, n=6)
tips.groupby('smoker').apply(top)
tips.groupby(['smoker', 'day']).apply(top, n=1, column='total_bill')
f = lambda x: x.describe()
tips.groupby(['smoker']).apply(f)
Explanation: 그룹 자체를 대체
apply 메소드는 수치값이 아닌 Group을 출력
단순히 대표값을 계산하는 것 뿐 아니라
순서 정렬, 일부 삭제 등 그룹 내의 레코드 자체를 변형하는 것도 가능
End of explanation
tips.pivot_table(index=['sex', 'smoker'])
tips.pivot_table(['tip_pct', 'size'], index=['sex', 'day'], columns='smoker')
tips.pivot_table(['tip_pct', 'size'], index=['sex', 'day'],
                 columns='smoker', margins=True)
tips.pivot_table('tip_pct', index=['sex', 'smoker'], columns='day',
                 aggfunc=len, margins=True)
tips.pivot_table('size', index=['time', 'sex', 'smoker'],
                 columns='day', aggfunc='sum', fill_value=0)
Explanation: pivot_table
pivot 명령과 groupby 명령의 중간적 성격
pivot을 수행하지만 데이터가 유니크하게 선택되지 않으면 aggfunc 인수로 정의된 함수를 수행하여 대표값 계산
디폴트 aggfunc 은 평균 계산
End of explanation
<END_TASK>