AICE (에이스) 시험 노트개념 정리12 MIN
행 고르기·조건 필터·그룹 집계
AICE Associate에서 표의 일부만 골라 내고 묶어 세는 자리입니다. loc과 iloc의 차이, 조건을 &로 잇는 불리언 인덱싱, groupby와 agg, sort_values와 pivot_table을 연습 문제 7개로 짚습니다.
표의 생김새를 읽었으면 다음은 필요한 부분만 골라 내는 자리입니다. AICE Associate는 「30세 이상 서울 고객의 평균 소득을 구하시오」·「지역별 구매 건수를 많은 순으로 출력하시오」처럼 조건과 집계를 한 줄로 묻는 문항을 여기서 냅니다. 손이 가장 자주 미끄러지는 자리이기도 한데, 이유가 셋 — loc과 iloc을 바꿔 쓰는 것, 조건을 and로 잇는 것, 집계 결과가 Series인지 DataFrame인지 헷갈리는 것입니다.
열 고르기
대괄호
대괄호를 한 겹 쓰면 Series, 곧 열 하나가 나오고 두 겹을 쓰면 DataFrame, 곧 표가 나옵니다. 값이 같은데 모양이 다릅니다.
df['Age'] # Series
df[['Age']] # DataFrame — 열 하나짜리 표
df[['Age', 'Income']] # DataFrame — 열 둘
이 구별이 중요한 자리가 모델 학습입니다. fit에 넣는 피처는 표여야 해서 X = df[['Age', 'Income']]으로 두 겹을 쓰고, 타깃은 열 하나여서 y = df['Churn']으로 한 겹을 씁니다.
drop
빼는 쪽이 편할 때는 drop을 씁니다. axis=1이 열, axis=0이 행입니다.
X = df.drop('Churn', axis=1) # 타깃만 빼고 전부 피처로
df = df.drop(['ID', 'Name'], axis=1) # 여러 개는 리스트로
drop은 지운 결과를 새로 돌려주고 원본은 그대로 둡니다. 원본을 바꾸려면 돌려받은 것을 다시 대입해야 합니다.
loc과 iloc
이름과 번호
loc은 이름으로, iloc은 번호로 고릅니다. 행 인덱스가 0부터 붙은 기본 상태에서는 둘이 같은 값을 돌려주어 차이가 안 보이는데, 인덱스를 ID로 바꿔 두면 곧바로 갈립니다.
df.loc[0, 'Age'] # 인덱스가 0인 행의 Age 열
df.iloc[0, 2] # 첫 번째 행의 세 번째 열
df.loc[:, 'Age':'Income'] # 이름으로 열 구간
df.iloc[:, 1:4] # 번호로 열 구간
iloc은 이름을 못 받습니다 — df.iloc[0, 'Age']는 ValueError가 납니다.
슬라이스의 끝
여기가 가장 자주 틀리는 자리입니다. iloc의 슬라이스는 끝을 뺀 파이썬 방식이고, loc은 끝을 포함합니다.
| 코드 | 나오는 행 |
|---|---|
df.iloc[0:3] |
0·1·2 — 세 행 |
df.loc[0:3] |
0·1·2·3 — 네 행 |
loc이 끝을 포함하는 이유는 받는 것이 번호가 아니라 이름이기 때문입니다. 이름은 「3 다음」이 무엇인지 알 수 없으므로 3까지 넣고 멈추는 편이 자연스럽습니다.
불리언 인덱싱
조건 하나
df['Age'] >= 30은 참·거짓이 행마다 들어 있는 Series를 돌려줍니다. 그것을 대괄호에 넣으면 참인 행만 남는데, 이 방식을 불리언 인덱싱이라고 합니다.
adults = df[df['Age'] >= 30]
print(adults.shape)
조건 둘
조건을 이을 때는 파이썬의 and·or가 아니라 &·|를 쓰고, 조건마다 괄호를 씌웁니다.
seoul_30 = df[(df['Age'] >= 30) & (df['City'] == 'Seoul')]
young_or_rich = df[(df['Age'] < 20) | (df['Income'] > 5000)]
and를 쓰면 ValueError: The truth value of a Series is ambiguous가 납니다. and는 양쪽을 각각 하나의 참·거짓으로 압축하려 드는데, 값이 1,000개 든 Series를 참 하나로 줄이는 방법이 정해져 있지 않기 때문입니다.
괄호를 빼면 오류가 다릅니다. &가 비교보다 먼저 계산돼서 30 & df['City']를 먼저 하려 들기 때문에 TypeError가 납니다.
isin과 between
값이 여럿 중 하나인지, 구간 안인지 볼 때는 전용 함수가 짧습니다.
df[df['City'].isin(['Seoul', 'Busan'])]
df[df['Age'].between(20, 29)] # 20 이상 29 이하 — 양끝 포함
df[df['Grade'] != 'C'] # 아닌 것
between은 양끝을 포함합니다. 「20대」를 고를 때 between(20, 30)으로 적으면 30세가 섞여 들어갑니다.
groupby
집계 함수
groupby는 지정한 열의 값이 같은 행끼리 묶고, 그 뒤에 붙인 집계 함수를 묶음마다 적용합니다.
df.groupby('City')['Income'].mean()
df.groupby('City').size() # 묶음마다 행 개수
df.groupby(['City', 'Grade'])['Income'].mean()
groupby만 쓰고 끝내면 묶기만 해 둔 객체가 나오고 값이 안 보입니다. 뒤에 mean·sum·count·size·max 같은 것을 반드시 붙입니다.
count와 size가 헷갈리는 짝입니다 — count()는 결측이 아닌 값만 세고 size()는 결측을 포함해 행 개수를 셉니다.
agg
여러 집계를 한 번에 내려면 agg에 목록이나 딕셔너리를 줍니다.
df.groupby('City')['Income'].agg(['mean', 'max', 'count'])
df.groupby('City').agg({'Income': 'mean', 'Age': 'median'})
결과의 인덱스가 묶음 이름이 되므로, 보통 열로 되돌려 놓는 편이 뒤 작업에 편합니다.
result = df.groupby('City')['Income'].mean().reset_index()
sort_values
오름차순과 내림차순
sort_values는 지정한 열을 기준으로 행을 줄 세웁니다. 기본이 오름차순이고 ascending=False가 내림차순입니다.
df.sort_values('Income', ascending=False).head(10) # 소득 상위 10명
집계 결과를 큰 순으로 보이라는 문항이 자주 붙으므로 groupby와 짝으로 익혀 둡니다.
df.groupby('City')['Income'].mean().sort_values(ascending=False)
여러 열
열을 리스트로 주면 앞에서부터 차례로 기준이 됩니다. 방향도 열마다 따로 줄 수 있습니다.
df.sort_values(['City', 'Income'], ascending=[True, False])
지역 이름은 가나다순으로, 그 안에서 소득은 큰 순으로 세운 것입니다. 인덱스가 섞여 따라오므로 필요하면 reset_index(drop=True)로 다시 매깁니다.
pivot_table
두 축
groupby가 묶음을 아래로 늘어놓는 데 반해 pivot_table은 한 축을 행, 다른 축을 열로 놓아 표로 펼칩니다. 갈래 둘의 조합을 한눈에 볼 때 씁니다.
pd.pivot_table(df, index='City', columns='Grade',
values='Income', aggfunc='mean')
지역이 행, 등급이 열, 칸마다 소득 평균이 들어간 표가 나옵니다. 같은 값을 groupby(['City', 'Grade'])로도 낼 수 있지만 그쪽은 줄이 조합 개수만큼 길게 늘어섭니다.
aggfunc
aggfunc의 기본값이 'mean'이라서 지정하지 않으면 평균이 나옵니다. 개수를 보려면 'count', 합을 보려면 'sum'을 줍니다. 조합이 하나도 없는 칸은 NaN이 되는데, fill_value=0을 주면 0으로 채웁니다.
이 영역의 출제 형태는 대개 셋입니다. 조건을 둘 이상 걸어 행을 고르게 하거나, 지정한 열로 묶어 평균이나 개수를 내게 하거나, 그 결과를 큰 순으로 세워 상위 몇 개를 출력하게 합니다.
연습 문제
다음 줄이 의도대로 동작하지 않는다. 무엇이 잘못되었고 어떻게 고치는가?
seoul_30 = df[df['Age'] >= 30 and df['City'] == 'Seoul']파이썬의and를 쓴 것이 잘못입니다.df['Age'] >= 30은 참·거짓이 행마다 든 Series인데and는 그것을 하나의 참·거짓으로 압축하려 하므로ValueError: The truth value of a Series is ambiguous가 납니다. 조건마다 괄호를 씌우고&로 이어df[(df['Age'] >= 30) & (df['City'] == 'Seoul')]으로 적습니다.인덱스가 0부터 붙은 표에서
df.iloc[0:3]과df.loc[0:3]이 각각 몇 행을 돌려주는가?iloc은 3행,loc은 4행입니다.iloc의 슬라이스는 끝을 뺀 파이썬 방식이라 0·1·2가 나오고,loc은 받는 것이 번호가 아니라 이름이라 끝을 포함해 0·1·2·3이 나옵니다.City가Seoul, Seoul, Busan, Busan, Busan, Daegu이고 같은 순서로Income이300, 500, 200, 400, 300, 600인 6행 표가 있다.df.groupby('City')['Income'].mean().sort_values(ascending=False)의 출력을 순서대로 쓰시오.Daegu600,Seoul400,Busan300입니다. Busan은 , Seoul은 , Daegu는 행이 하나라 600입니다. 내림차순이라 큰 값부터 섭니다.20대 고객만 고르려고
df[df['Age'].between(20, 30)]이라고 적었다. 무엇이 잘못되었는가?between은 양끝을 포함하므로 30세가 함께 들어옵니다.between(20, 29)로 적거나df[(df['Age'] >= 20) & (df['Age'] < 30)]으로 씁니다.모델 학습에 쓸 피처로
Age와Income두 열을 고를 때 알맞은 것은?
①X = df['Age', 'Income']
②X = df['Age']['Income']
③X = df[['Age', 'Income']]
④X = df.iloc['Age', 'Income']③. 열 여러 개는 이름을 리스트로 묶어 대괄호 두 겹으로 넘기고, 결과가 DataFrame이라fit에 바로 들어갑니다. ①은 튜플을 열 이름으로 찾아KeyError, ②는 Series에 다시 열 이름을 찾는 것이라 오류, ④는iloc이 이름을 못 받아ValueError입니다.df.groupby('City')['Income'].count()와df.groupby('City').size()는 무엇이 다른가?count()는 지정한 열에서 결측이 아닌 값만 세고,size()는 결측을 포함해 그 묶음의 행 개수를 셉니다.Income에 빈 칸이 있는 지역에서는count()가size()보다 작게 나옵니다.지역을 행, 등급을 열로 놓고 칸마다 구매 건수를 세는 표를 만들려 한다. 조합이 없는 칸은 0으로 채우시오.
pd.pivot_table(df, index='City', columns='Grade', values='ID', aggfunc='count', fill_value=0)입니다.aggfunc의 기본값이'mean'이므로 개수를 세려면'count'를 직접 주어야 하고,fill_value=0이 조합이 없어NaN이 된 칸을 0으로 바꿉니다.
여기서 손이 굳어야 하는 것은 네 줄입니다 — df[(조건) & (조건)], groupby('열')['열'].mean(), sort_values(ascending=False), df[['열', '열']]입니다. 골라 세는 것까지 됐으면 다음은 그 안에 든 빈 칸과 겹친 행, 튀는 값을 찾아 내는 자리이고, 거기서 isnull().sum()과 duplicated, 사분위로 이상값 후보를 잡는 IQR을 다룹니다.

