SKN_13th

[플레이데이터 SK네트웍스 Family AI 캠프 13기] 4주차 회고

8000gam 2025. 4. 20. 14:26

평온한 주말 오후다. 오늘은 오랜만에 머리를 자르고 태블릿을 챙겨 근처 카페로 나섰다. 자리를 잡고 따뜻한 커피를 한 모금 씩 홀짝일 때마다 한 주가 끝났다는 실감이 든다. 입과 이후 4주, 빠르게 흘러간 약 한 달이라는 시간이 지났다. 오랜만에 여유를 즐기고 있어서 그런지, 지난 날들이 더욱 바빴다고 느껴진다. 파이썬 기초, SQL, streamlit, 미니 프로젝트, 그리고 이번주에 배우기 시작한 새로운 것들. ”지금까지 많은 것을 배웠구나“ 싶다가도 남은 다섯 달을 생각하면 이제 시작이라는 생각도 든다. 그래도 오늘만큼은 앞으로에 대한 생각은 접어두고 편안하게 돌아보면서 휴식을 취하고자 한다.

💻 What?

1. 머신러닝, 딥러닝을 위한 여러 라이브러리

이번주는 5일 내내 pandasmatplotlib을 익히는 시간이었다. pandas는 1차원 자료구조인 Series와 2차원 자료구조인 DataFrame을 핸들링하는 데 특화된 라이브러리이다. 얼마 전 배웠던 SQL이 특정 테이블에서 원하는 값들만 추려서 보여주거나, 테이블에 원하는 값을 추가하거나 삭제하는 등, 테이블 관련 여러 기능을 지원했는데, pandas도 유사하거나 동일한 기능들을 지원한다. python판 sql이라고 보면 되겠다. matplotlib은 위 자료구조들에 대한 시각화를 도와주는 라이브러리다. 우리는 그 중 pyplot이라는 2차원 데이터 시각화 전문 모듈에 대해 배웠고, line chart, scatter plot, histogram, boxplot 등 다양한 통계적 시각화 기능을 지원한다. 다음주에는 numpy라는 다차원 배열 연산 라이브러리를 이어서 배울 예정이다.

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

2. 코딩 테스트 스터디

월요일에 첫 코딩 테스트 스터디를 진행했다. PCCE 수준 문제 4개와 PCCP 수준 문제 1개를 풀어온 뒤, 팀장님이 이에 대한 해설을 해주시고, 서로 어려웠거나 궁금했던 점을 토의하는 시간을 가졌다. 이후 시간이 조금 남아서 백준 온라인 저지 문제 한 개를 같이 고민하며 풀어보는 시간을 가졌다. 이후 GitHub에 스터디 전용 개인 Repository를 만든 뒤, 내 소스 코드와 피드백, 그리고 총평을 올렸다.

😮 So What?

평이했다...?

이번주는 전반적으로 따라갈 만했다. pandas는 과거 빅데이터분석기사 실기 시험을 준비할 때 같이 살다시피 했고, matplotlib도 학교 팀 프로젝트를 수행할 때 비슷한 시각화 라이브러리인 seaborn과 함께 자주 사용했던 친구들이기 때문에, 나에게 이번 주는 리마인드를 위한 시간이었던 것 같다. 그럼에도 생소했던 것들이 몇 가지 있었기에, 이 부분들만 간단히 짚어보겠다.

  • DataFrame.query()

pandas DataFrame은 boolean indexing을 통해 특정 조건을 만족하는 관측치들만 조회해 볼 수 있다. 즉, 특정 조건절을 통해 True로 평가되는 관측치들만 선택하여 조회할 수 있다. 여러 사람들의 인적 사항이 담긴 테이블이 df라는 변수 안에 담겨 있다고 가정하자. 각 column을 구성하는 요소는 이름, 나이, 성별, 지역, 흡연 여부 등의 다양한 인적 사항이다. 우리는 이들 중 성인 남성의 데이터만 조회해보고 싶다. 이 때 다음과 같이 boolean indexing을 통해 성인 남성 관측치만 선별해서 조회할 수 있다.

df_men = df[(df['gender'] == '남') & (df['age'] >= 19)]    
# 성별은 남자, 나이는 만 19세 이상.
df_men.head()


# 변수에 따로 저장하지 않아도 조회 결과를 보여주긴 한다.
# 조회 이외에 다른 용도가 있다면 변수에 저장하여 사용한다.

 

.query() 메소드는 boolean indexing과 동일한 기능을 수행한다. 그런데 표현 방식에 있어 .query()가 조금 더 자유로운 편이다. 상기 예시와 동일한 조건으로 비교하는 아래의 .query() 사용 예시를 살펴 보면 이를 알 수 있다.

df_men = df.query("gender == '남' and age >= 19")
df_men.head()

# 문자열에 표현한다.
# boolean indexing은 한 번에 여러 조건을 걸 때 각각의 조건을 괄호()로 감싸고 
# 비트 연산자(&, |, ~)를 통해 조건 별 논리 우선 순위를 걸어야 했다.
# 반면 .query()는 여러 조건을 괄호로 감쌀 필요도 없고
# 일반 논리 연산자(and, or, not)를 그대로 사용할 수 있다.

 

그러나 어떤 면에서 보면 boolean indexing이 자유도가 더 높은 편이다. 여러 영화에 대한 정보들이 담겨 있는 테이블이 movie라는 변수 안에 저장되어 있다고 가정하자. 우리는 이들 중 감독 이름에 'John'이 들어가는 영화만 조회하고 싶다. 그 과정에서 결측치(감독 이름 누락)는 제외하고 싶다. 이를 위해 우선 Series 객체의 속성과 메소드 Series.str.contains()를 통해 특정 문자열의 포함 여부를 확인해 볼 수 있겠다. 별도 설정 없이 사용한다면 결측치와 마주쳤을 때 연산 오류가 발생하기 때문에, contains()의 파라미터를 커스터마이징해준다(na = False). boolean indexing에서는 이게 가능하지만, query()에서는 조건절을 함수나 메소드로 표현할 때 파라미터 설정을 할 수 없다. 따라서 query()를 사용할 경우, 결측치를 별도로 처리해야 한다.

# Boolean Indexing
movie[movie["director_name"].str.contains("John", na = False)]

# .query()
movie.query("director_name.notna() and director_name.str.contains('John')")

 
정리하고 나니 상황에 맞게 더 간결하게 표현할 수 있는 방법을 선택해서 사용하거나, 그게 어렵다면 boolean indexing으로 일관된 표현 방식을 사용하는 것이 낫겠다는 생각이 든다. 내가 사용하고자 하는 함수나 메소드에 대해 자세히 알고 있다면, 나중에는 이 방법이 더 간결하고 코드 해석도 쉬울 것이라는 게 나의 개인적인 견해다.

  • matplotlib

matplotlib도 자유도가 높다는 건 알았지만, 이렇게까지 내 맘대로 그래프를 그릴 수 있을 줄은 몰랐다. 그래프 색상 세부 설정, 그래프 투명도 설정, 범례 위치 설정 등 할 수 있는게 너무나도 많다. df에 연도별 미세 먼지 관련 정보들이 담겨 있고, column은 다섯 개로 구성되어 있다. '주의보 발령횟수', '주의보 발령일수', '경보 발령횟수', '경보 발령일수', '최대농도' 순이다('최대농도'는 df.columns[-1]에 위치, 나머지는 df.columns[:-2]로 슬라이싱 가능). 빈도수 그래프 Line Chart와 농도 그래프 Line Chart를 그리고 싶다면 다음과 같이 코딩할 수 있겠다.

fig = plt.figure(figsize = (6, 8))

# 빈도 그래프
ax1 = fig.add.subplot(2, 1, 1)            
# 그래프를 위아래로 하나씩 배치해요. 이 그래프는 그 중 위(1번)에 그려요.
for i in df.columns[:-2]:
    ax1.plot(df.index, df[i], label = i, alpha = 0.5)    
    # 투명도를 50%로 설정해서, 그래프끼리 겹쳐도 인식할 수 있어요.
ax1.set_title('연도별 주의보 및 경보 빈도')
ax1.legend()

# 농도 그래프
ax2 = fig.add_subplot(2, 1, 2)	# 이 그래프는 아래(2번)에 그려요.
ax2.plot(df.index, df['최대농도'], label = '최대농도', 
        color = '#020715', linestyle = '--')    
        # 점선으로 표시해요. 색상을 hex code로 지정할 수도 있어요.
ax2.set_title('연도별 최대농도')
ax2.legend(bbox_to_anchor = (1.02, 1), loc ='upper left')                    
# 범례 위치를 커스터마이징할 수 있어요.

plt.show()

 
강사님이 하신 말씀이 기억에 남는다. 자유도가 높아서 뭐든 할 수 있다. 우리가 할 일이 많다는 뜻이다. 표현할 수 있는 것들이 많아도 우리가 일일이 설정해야 하기 때문에, 결국 사용자가 아는 게 많아야 되겠다.

🎈 Now What?

집으로 돌아가면 일단 다음 주 화요일에 있을 코딩 테스트 스터디를 준비해야겠다. 저번주 문제들은 읽어 보면 그래도 어떻게 풀지 감이라도 잡혔었는데, 이번주에 받은 다섯 문제는 아예 차원이 다른 것 같다. 지금 당장은 도저히 어떻게 접근해야할 지 엄두조차 나지 않는다. 저번 스터디에서는 코린이 나름대로 건설적인 의견도 내보고 적극적으로 피드백에 참여했지만, 이번주에는 팀원들의 도움을 많이 받아야 할 지도 모르겠다.
 

그리고 numpy 예습을 해볼까 싶다. 나는 지금까지 습관성 import로 불러왔던 라이브러리인데, 강사님의 예고를 들어보니 머신러닝&딥러닝에서는 모든 것이 numpy라고 한다. 위의 두 라이브러리에서도 내가 몰랐던 것들이 존재했듯, numpy도 분명히 그런 부분들이 있으리라.

 
어쨌든 본격적인 AI 기술 강의가 시작된다면 그 날 배운 내용을 정리하는 것도 벅찰 지도 모른다. 앞으로의 일정을 위해 오늘은 쉼에 초점을 두고 열심히 달려온 나를 달래려 한다.

여담

금요일에 수업이 끝난 뒤 가고 싶은 카페가 있어 문래동으로 발걸음을 옮겼다. 집으로 돌아가는 길에 겹벚꽃 한 그루를 봤다. 올해는 꽃구경을 제대로 하지 못하고 흘려 보내겠구나' 싶었는데 길가에 서 있던 딱 한 그루. 홀로 핀 모습이 아름다워 나무 아래에 꽤나 오래 머물러 있었다.