KT AIVLE School/[TIL] AIVLE School 당일 복습

[TIL] [KT AIVLE School] KT 에이블스쿨 6기(DX 트랙) 2주차 5일. 데이터 다듬기 - pandas DataFrame 조회 / DataFrame 집계

guoyee94 2024. 9. 13. 21:55

 

목차
 1) 데이터프레임 조회 - loc() iloc()
 2) 데이터프레임 집계 - gruopby()
 3) 집계함수

 

 

 

쏜살같이 흘러간 교육 2주차.

 

추석 연휴를 앞둔 마지막 시간이니만큼 많은 것들을 배웠다.

 

저번에 데이터를 요리조리 뜯어보는 과정을 배웠다면,

이번에는 데이터에서 의미를 도출할 때 필요한 도구들을 배웠단 느낌이다.

비슷해 보이지만 아무튼 다르다.

 

오늘 과정의 핵심을 요약하자면 .loc[].groupby()를 들 수 있겠다.

 

따라서 오늘의 포스팅은 이 둘을 중심으로 진행되겠다.

 

강사님께서 마지막에 matplotlib.pyplot을 이용한 시각화도 다뤄 주셨는데,

그래프 색깔 바꾸면서 노느라 나중에 다시 나올 내용이라고 하셔서 온전히 집중하진 못한 것 같다.

 

어쩔 수 없는 ENFP 나자신.

 

 


 

데이터프레임 조회 : loc[]

 

데이터 분석을 해 봤거나 AICE를 준비해 본 사람이라면 알겠지만,

 pandas DataFrame을 보다 보면, 거의 매 셀마다 조회/집계를 하게 된다.

 

그 정도 양이면 아무래도 직관적으로 데이터테이블을 펼쳐놓을 순 없으니까.

 

여튼 그럴 때 가장 애용할만한 방법이 바로 loc(Location) 메서드다.

 

기본적인 사용법은 df.loc[  행, 열  ] 형태로 원하는 values를 집계하는 것이다.

 

loc은 메서드지만 뒤에 대괄호[]가 붙는다는 점을 주의하자.

 

tip.loc[10, 'total_bill']  ## 'tip'데이터프레임 total_bill열 10번행 조회

 

이게 기본이다. df.loc[행, 열] 잊지 말자.

 

iterable한 객체에서 대괄호를 사용해 값을 불러온다는 점이

리스트나 튜플의 인덱싱, 슬라이싱과 비슷하다.

 

그걸 증명하듯 슬라이싱도 가능하고, 열들을 리스트로 묶어서 처리도 가능하다.

 

tip[:, 'total_bill']       ## 'tip'데이터프레임 total_bill열 모든 행 조회

tip.loc[:5, :]             ## 'tip' 데이터프레임의 5번행까지, 모든 열 조회

tip.loc[: ,['total_bill', 'tip']]
                           ## 'tip'데이터프레임 total_bill열, tip열 모든 행 조회

 

 

 

또한 이때, 열이 하나면 기본적으로 Series를 반환한다.

 

물론, 둘 이상이면 어쩔 수 없이 DataFrame을 반환한다.

 

지난 시간에 봤듯, Series는 열을 하나만 가질 수 있기 때문이다.

 

이를 이용해, 컴퓨터에게 '데이터프레임인 척'을 함으로써 ??? : 의지를 보여주는 겁니다.

 

데이터프레임을 반환받을 수 있다.

 

열이 하나라도 리스트 형태로 전달하는 것이다.

 

tip['total_bill']

시리즈가 반환된다.

 

 

tip[['total_bill']]

데이터프레임이 반환된다.

 

예전에 AICE 준비할 때는 이 원리를 도무지 이해를 못했는데,

역시 스승이 계신 것은 중대사다.

 


 

# tip 열만 조회
tip.loc[:, 'tip']

# tip, day, time 열만 조회
tip.loc[:,['tip', 'day', 'time']]

# tip, day, time 열만 tip 열 기준으로 내림차순 정렬해서 10개 행만 조회
tip.loc[:, ['tip', 'day', 'time']].sort_values(by='tip', ascending=False)[:10]

# sex ~ time 열 조회
tip.loc[:, 'sex':'time']

 

보다시피, DataFrame에서는 보통 열(columns)이 조회된다.

 

그런데 조건도 잘 주지 않는 행 자리에 매번 ' :, '를 넣는 것도 번거로운 일.

 

그래서 pandas 제작자는 우리에게 편의를 제공한다.

 

df.loc[:, '열']   =   df['열']

 

행에 조회 조건이 없으면 .loc행 범위 지정을 안 해도 되는 것이다.

 

따라서 위에 있는 코드들은

 

# tip 열만 조회
tip['tip']

# tip, day, time 열만 조회
tip[['tip', 'day', 'time']]

# tip, day, time 열만 tip 열 기준으로 내림차순 정렬해서 10개 행만 조회
tip[['tip', 'day', 'time']].sort_values(by='tip', ascending=False)[:10]

# sex ~ time 열 조회
tip['sex':'time']

 

이렇게 표기 가능하다..... 면 좋겠다만,

딱 하나, 맨 아래에 tip['sex':'time'] 요녀석은 에러가 난다.

 

즉, 슬라이싱에서는 loc 생략이 불가능하다.

 

정리하자면

  • df.loc[행, 열]을 통해 데이터 조회가 가능하다.
  • 단 행에 조건을 주지 않고 전체 행을 조회한다면, df[열]로 줄여 쓸 수 있다.
  • 슬라이싱을 쓸 때는 줄여 쓸 수 없다.

 

아 그리고 하나 더, loc이라는 인덱서는

(강사님의 표현을 빌리자면) '인간적인' 검색이다.

 

좀 더 의미적으로 적절하게 말하자면, 직관적인 인덱서다.

 

파이썬 특유의 'n  바로 앞까지'가 적용되지 않는다.

 

이를테면 이런 거지.

왼쪽은 head(), 오른쪽은 loc[]

 

똑같이 매개변수를 5로 줬지만, loc은 5번 인덱스까지 같이 꺼내 온다. 주석 무엇

 


 

그리고, 어쩌면 가장 중요한 일.

 

loc은 무려 조건 검색이 된다.

 

# tip 열 값이 6.0 보다 큰 행 조회
tip.loc[tip['tip']>6.0, 'tip']

# tip 열 값이 6.0 보다 큰 행 조회(조건을 변수에 할당)
target = tip['tip'] > 6.0
tip.loc[target, 'tip']

# and로 여러 조건 연결 (tip > 6.0 and day == Sat)
tip.loc[(tip['tip'] > 6.0) & (tip['day'] == 'Sat')]

# or로 여러 조건 연결 (tip > 6.0 or day == Sat)
tip.loc[(tip['tip'] > 6.0) | (tip['day'] == 'Sat')]

# 조건에 맞는 하나의 열 조회
tip.loc[tip['size'] >= 5, ['tip']]

# 조건에 맞는 여러 열 조회
tip.loc[tip['size'] >= 5, ['total_bill', 'tip', 'size']]

 

데이터 만져본 거라곤 AICE Associate 준비때랑 시험 때 좀 해본 게 다지만,

그때마다 loc의 조건 검색은 거의 구세주였던 걸로 기억한다.

 


 

마지막으로, 데이터 조회 시 자주 병용되는 메서드 isin()between()을 알아보자.

 

# 값 나열 (day가 Sat 또는 Sun)          ## '또는'이라는 점 유의
tip.loc[tip['day'].isin(['Sat', 'Sun'])]  ## 단일 조건에 대해 따지더라도 꼭 리스트 형태!

# 범위 지정 ( 1 <= size <= 3)           ## 머리 꼬리 포함
tip.loc[tip['size'].between(1, 3)]

 

isin()은 데이터프레임이나 시리즈(위의 경우는 tip['day']이니까 시리즈)가

괄호 안의 요소들 중 하나를 가지고 있냐를 row마다 따져서

bool 값을 반환한다.

 

따라서 loc[] 안에 넣으면 True인 애들만 뽑아서 조회한다.

 

between()은 괄호 안에 값의 범위를 넣어서 그것에 만족하는 값들을 조회할 때 쓴다.

물론 이것도 단독으로 쓰면 bool 값 반환하는 듯.

 

 

 

 


 

데이터프레임 집계 : groupby()

 

 

나왔다. 올해 봄에 독학하던 나를 가장 크게 괴롭힌 주범.물론 merge랑 concat 이놈들도 잊지 않았다.

 

다만... 강사님께 배우니 뭔가... 허탈하달까? 개념이 막 어려운건 아니었다.

 

역시 스승은 중요하다.

 

각설, groupby()는 기본적으로 범주형 데이터를 기준으로 연속형 데이터를 집계할 때 쓴다.

 

범주형 데이터, 연속형 데이터

말 그대로 연속형 데이터는 연속적인 수치, 범주형 데이터는 불연속적인 범주를 갖는 데이터다.

달리 말하자면
연속형 데이터는 합, 평균, 분산, 표준편차 등을 갖는 데이터.
예를 들면 키, 점수, 인구수 등이다.

범주형 데이터는 카테고리를 나눌 수 있는 데이터.
예를 들면 성별, 세대, 거주지역 등이 되겠다.

보통 연속형 데이터는 int, float이고 범주형 데이터는 str이지만,
합격/불합격을 1/0으로 나타내는 등 범주형도 수치화될 수 있다.

 

그래서 groupby() 어떻게 쓰느냐.

 

기본 형식은 이렇게 생겼다.

 

데이터프레임.groupby(by = '기준열(범주)', as_index=False)[['집계열(연속)']]

 

as_index 파라미터와, 집계열을 이중 대괄호로 묶는 것은 연구자의 재량이지만

 

에이블러들은 일단 위의 형식을 고정적으로 쓰기로 했다. 응애

 


 

또 한가지, 저 포맷의 끝에 보통 집계함수라는 것이 붙는다.

 

집계란게 결국 유의미한 데이터를 요하기 때문에 보통 대상이 합, 평균 등이거든.

 

집계함수는 다음과 같다. 보통 axis = 0 고정.(서로 다른 열 값을 합칠 필요는 없으니까.)

 

sum()
mean() 산술평균
median() 중앙값
mode() 최빈값, 범주형에도 쓸 수 있다.
min() 최솟값
max() 최댓값

 

이외에 4분위수 같은 것도 구할 수 있는 것 같은데... 아직 잘 모르겠다.