내일배움캠프

[내일배움캠프] TIL 24일차 26.02.03(화)

nom_de_plume 2026. 2. 3. 20:19

종합 성취도 평가 해설.

A. SQL (Q1–Q4)

Q1. AVG와 NULL 🧰 필수

테이블 t_score가 아래와 같을 때, 결과로 올바른 것은?

score
5
NULL
3
SELECT AVG(score) AS avg_score
FROM t_score;

A. 2.666…

B. 4.0

C. 8.0

D. NULL

답) B

NULL은 COUNT() 외의 집계함수에는 포함 x

 

Q2. BETWEEN 동작 🧰 필수

MySQL에서 BETWEEN에 대한 설명으로 가장 올바른 것은?

A. 시작값만 포함하고 끝값은 포함하지 않는다

B. 시작값/끝값을 모두 포함한다

C. 문자열에서는 동작하지 않는다

D. NULL이 있으면 항상 에러가 난다

답) B

동일한 의미라 시작값, 끝값 포함

 

Q3. 2026-01-03 Comedy 평점 리스트 🧰 필수

아래 조건을 만족하는 평점 리스트를 출력하는 SQL을 작성하세요.

  • 대상 날짜: rated_at의 날짜가 '2026-01-03'
  • 영화 조건: movies.genre = 'Comedy' AND movies.is_available = 1
  • 평점 조건: review_status IN ('OK','SUSPECT')
  • 평점값 조건: rating이 NULL이 아니어야 함
  • 출력 컬럼:
    • rated_at, city, title, rating, review_status
  • 정렬: city 오름차순, user_id 오름차순

사용 테이블: ratings r / movies m / users u

 

[실행 결과]

답) 

select
	r.rated_at,
	u.city,
	m.title,
	r.rating,
	r.review_status
from ratings r
join movies m
	on r.movie_id = m.movie_id 
join users u
	on r.user_id = u.user_id 
where DATE(r.rated_at) = '2026-01-03'
	and m.genre = 'Comedy'
	and m.is_available = 1
	and r.review_status in ('OK','SUSPECT')
	and r.rating is not null
order by
	u.city asc,
	r.user_id asc;

is not null 누락 -> 결과 동일해도 조건 불일치로 오답

 

Q4. 도시별 평균 평점 TOP 1 🚀 도전

Q3과 동일한 필터 조건으로, 도시별 평균 평점을 구한 뒤 평균이 가장 높은 도시 1개만 출력하세요.

  • 출력 컬럼:
    • city
    • avg_rating (소수 1자리 반올림)
    • rating_cnt (해당 조건에 포함된 평점 개수)
  • 정렬: avg_rating 내림차순, city 오름차순
  • 결과는 1행만

[실행 결과]

답)

select
	u.city,
	round(avg(r.rating) ,1) as avg_rating,
	count(*) as rating_cnt
from ratings r
join movies m
	on r.movie_id = m.movie_id 
join users u
	on r.user_id = u.user_id 
where DATE(r.rated_at) = '2026-01-03'
	and m.genre = 'Comedy'
	and m.is_available = 1
	and r.review_status in ('OK','SUSPECT')
	and r.rating is not null
group by u.city
order by
	avg_rating desc,
	u.city asc
limit 1;

is not null 누락 -> 결과 동일해도 조건 불일치로 오답

 

B. Python (Q5–Q8)

Q5. set의 길이 🧰 필수

s = {"a", "b", "a"}
print(len(s))

A. 3

B. 2

C. 1

D. 에러

답) B

집합 자료형은 갯수를 셀 때 중복을 제거한다.

 

Q6. 기본 인자 함정 🚀 도전

def add_item(x, items=[]):
    items.append(x)
    return items

print(add_item(1))
print(add_item(2))

A. [1] / [2]

B. [1] / [1, 2]

C. [] / [1, 2]

D. 에러

답) B

함수에서 기본 인자값이 리스트의 형태로 지정되어 있기에 함수 정의할 때, 처음 호출하면 할당, 그 이후에는 값이 누적으로 삽입된다.

 

Q7. 리뷰 상태가 BAD인지 판별 🧰 필수

아래 조건을 만족하는 함수 is_bad(review_status, rating)를 작성하세요.

  • review_status == "BAD" 이면 True
  • rating이 None이면 True
  • 그 외는 False

예:

  • is_bad("OK", 4) → False
  • is_bad("BAD", 5) → True
  • is_bad("OK", None) → True

답)

## Q7 튜터님 풀이
def is_bad(review_status, rating):
    if review_status == "BAD":
        return True
    if rating == None:
        return True
    return False

Q8. None을 무시하고 합 구하기 🧰 필수

리스트 values에서 None은 무시하고 나머지 숫자만 합을 반환하는 함수 sum_ignore_none(values)를 작성하세요.

예:

  • sum_ignore_none([1, None, 3]) → 4

답)

def sum_ignore_none(values):
    total = 0
    for value in values:
        if value is None:
            continue
        total += value
    return total

 

C. 전처리(Pandas) (Q9–Q14)

Q9. to_numeric + errors="coerce" 🧰 필수

import pandas as pd

s = pd.Series(["3", "x", "5"])
out = pd.to_numeric(s, errors="coerce")
print(out.tolist())

A. [3, 0, 5]

B. [3, "x", 5]

C. [3.0, nan, 5.0]

D. 에러

답) C

errors="coerce"는 숫자로 변환 불가능한 값을 nan으로 강제 변환

 

Q10. duplicated의 기본 keep 🧰 필수

import pandas as pd

df = pd.DataFrame({"user_id": ["U1", "U1", "U2"]})
print(df.duplicated(subset=["user_id"]).sum())

A. 0

B. 1

C. 2

D. 3

답) B

duplicated의 기본값 keep=first이다. (처음 나온 것은 유지, 나머지는 중복이라고 명시)

첫등장은 False라서 0, 중복 등장은 True라서 1이기에 0,1,0되서 sum()하면 1이 된다. 

 

Q11. fillna(inplace=True) 반환값 🚀 도전

import pandas as pd

df = pd.DataFrame({"x": [1, None]})
result = df["x"].fillna(0, inplace=True)

print(result)

A. 0

B. [1, 0]

C. None

D. 에러

답) C

(함정문제) inplace=True는 원본을 바로 대체해서 작업할 것이라는 뜻

그래서 result로 받으면 None이 나온다. result로 받기 위해서는 fillna(0)이라고만 입력하면 된다.

inplace 쓰려면 result 제거, inplace 안쓰면 result 필요

Q12. 데이터 로드 & 기본 확인 🧰 필수

users.csv, movies.csv, ratings.csv를 불러오고 아래를 수행하세요.

  1. 각 데이터프레임의 shape 출력
  2. ratings에서 head(2) 출력
  3. (권장: ratings는 parse_dates=["rated_at"])

[실행결과]

답)

## Q12 튜터님 풀이
import pandas as pd

users_df = pd.read_csv("users.csv")
movies_df = pd.read_csv("movies.csv")
ratings_df = pd.read_csv("ratings.csv", parse_dates=["rated_at"])

print(users_df.shape, movies_df.shape, ratings_df.shape)
ratings_df.head(2)

 

Q13. 중복 제거 + 숫자 변환 + 병합 + 필터 🧰 필수

아래 순서대로 처리하세요.

  1. ratings에서 (user_id, movie_id, rated_at) 기준 중복 개수 출력
  2. 위 기준으로 drop_duplicates(keep="first") 적용
  3. rating_num 컬럼 생성: pd.to_numeric(rating, errors="coerce")
  4. movies, users를 차례대로 left merge 해서 df_full 생성
  5. 아래 조건으로 필터링하여 df_clean 생성
    • is_available == 1
    • review_status가 OK 또는 SUSPECT
    • rating_num이 결측치가 아님
  6. df_clean의 행 개수 출력

[실행 결과]

답)

result = (
    df_clean.groupby(['city','genre'])
    .agg(
        rating_cnt = ('rating_num','size'),
        avg_rating = ('rating_num', 'mean')
    )
    .reset_index()
)

result['avg_rating'] = result['avg_rating'].round(1)
result = result.sort_values(['city','genre'], ascending=[True, True])
result

 

 

D. 시각화(Matplotlib/Seaborn) (Q15–Q18)

Q15. boxplot 해석 🧰 필수

boxplot(박스플롯)에 대한 설명으로 가장 올바른 것은?

A. 박스는 평균을 의미한다

B. 박스는 사분위수(분포의 일부)를, 수염은 나머지 분포(이상치 제외)를 표현한다

C. 수염은 항상 최소/최대값이다

D. boxplot은 범주형 데이터에만 쓸 수 있다

답) B

박스 = 사분위수

수염 = 이상치 제외 나머지 분포

수염 밖 값 = 이상치

 

Q16. x축 라벨 겹침 해결 🧰 필수

날짜 라벨이 겹칠 때 가장 흔한 해결 방법은?

A. plt.xticks(rotation=45) 또는 ax.tick_params(rotation=45)

B. df.reset_index()

C. df.astype(int)

D. plt.legend()

답) A

라벨이 겹치면 각도 조절 혹은 공간을 넓혀야 한다.

B,C 는 판다스

D는 범례 설정에 사용

 

Q17. 평점 분포 히스토그램 🧰 필수

ratings.csv를 불러온 뒤, 아래 조건에 맞는 평점(rating)의 분포를 히스토그램으로 시각화하세요.

  • 데이터 로드
    • ratings = pd.read_csv("ratings.csv", parse_dates=["rated_at"]) 권장
  • 포함 조건(필터)
    • review_status가 "OK" 또는 "SUSPECT"
    • rating이 결측치가 아닌 행만
    • 중복 제거는 하지 않습니다(그대로 사용)
  • 그래프 요구사항
    • 히스토그램(histogram) 형태 (seaborn의 histplot 사용 가능)
    • 제목/축 라벨 포함
    • (권장) plt.tight_layout() 적용, bin = 5 권장

[실행 결과] - bin에 따라 모양은 달라질 수 있음.

답)

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

ratings = pd.read_csv("ratings.csv", parse_dates=["rated_at"])

df = ratings[
    ratings["review_status"].isin(["OK", "SUSPECT"]) &
    ratings["rating"].notna()
].copy()

plt.figure(figsize=(6, 4))
sns.histplot(data=df, x="rating", bins=5)
plt.title("Rating Distribution (OK/SUSPECT)")
plt.xlabel("Rating")
plt.ylabel("Count")
plt.tight_layout()
plt.show()

 

Q18. 리뷰 상태별 평점 개수 막대그래프 🧰 필수

ratings.csv를 불러온 뒤, review_status별 평점(리뷰) 개수를 막대그래프로 시각화하세요.

요구사항

  • 데이터 로드
    • ratings = pd.read_csv("ratings.csv")
    • (선택) parse_dates=["rated_at"]를 사용해도 OK
  • 집계/그래프
    • x: review_status
    • y: 각 상태의 개수(count)
    • seaborn의 countplot 사용 권장 (사전 집계 없이 자동 count)
  • 그래프 꾸미기(최소)
    • 제목(title), x/y 축 라벨(label) 포함
    • plt.tight_layout() 적용
  • 다만, 그래프가 보여질 때 왼쪽부터 OK, SUSPECT, BAD 순이어야 한다.

[실행 결과]

답)

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

ratings = pd.read_csv("ratings.csv", parse_dates=["rated_at"])

plt.figure(figsize=(6,4))
sns.countplot(data=ratings, x='review_status', order=['OK','SUSPECT','BAD'])
plt.title('Count of Ratings By Review Status')
plt.xlabel('review_status')
plt.ylabel('count')
plt.tight_layout()
plt.show()