패캠 | 패스트캠퍼스 부트캠프/Python 🐍
패캠 4주차 학습일지 | 데이터 전처리 & 시각화 루틴 복습일지 with Plotly 🧹
mean_so
2025. 5. 20. 23:39
오늘은 여러 가지 데이터를 가지고 데이터 가공부터 전처리, 분석까지 진행해 보았는데요 !
공통적으로 시행되는 단계들을 정리해보았어요
colab환경에서 분석을 해보았습니다 !
단계 오늘의 데이터 분석 진행 과정 정리 🚀
- 데이터 마운트하기
- 구글 드라이브나 외부 데이터를 Colab에 연결하여 불러옵니다.
- head() 함수로 데이터 살펴보기
- 데이터의 첫 몇 줄을 확인하여 구조와 내용을 파악합니다.
- 컬럼별 의미도 함께 확인해 봅니다.
- 분석 질문 만들기
- 데이터를 통해 답하고 싶은 질문을 정리합니다.
- 데이터 전처리하기
- 분석에 사용할 컬럼만 남깁니다.
- 필요한 경우, 분리된 데이터를 merge() 함수로 합칩니다.
- 중복된 컬럼이나 행이 있다면 drop() 함수로 정리합니다.
- 질문에 맞춰 새로운 컬럼을 생성합니다.
- 데이터 타입을 적절히 변환합니다.
예) ID는 고유 값이니 문자열(str)로, 날짜 데이터는 pd.to_datetime()을 이용해 날짜 형식으로 변환 - info() 함수로 데이터 타입이 잘 변환됐는지 확인합니다.
- 결측치가 있는지 info()나 isnull()로 확인 후, dropna()로 제거합니다.
- 전처리 후 head() 함수로 최종 데이터 형태를 다시 확인합니다.
- 3번에 만들었던 질문에서 필요한 데이터가 있다면 기존컬럼들을 이용하여 새로운 컬럼 만들기
- ex. id와 같은 값은 고유한 값으로 str로 바꿔주기 / date는 날짜 형식이기 때문에 날짜로 바꿔주기
- 이때 pandas에서 날짜로 바꿔주는 함수는 to_datetime
- 데이터 타입 변경할건 변경하기
data['release_date'] = pd.to_datetime(data['release_date'], format='%Y-%m-%d') #년-월-일이였으니까 포맷을 맞춰서
- 대신 요로캐 포맷은 맞춰줘야함
- info() 함수를 통해 데이터 타입 잘 변환되었는지 확인하기
- 한번더 info()함수를 불러와 결측치 확인하기
- dropna()함수를 통해서 결측치 제거하기
- 데이터 가공을 다했으면 head()함수로 전처리 준비가 완료되었는지 확인하기
5. 분석 및 시각화
- plotly 라이브러리 등의 시각화 도구로 그래프를 그려 분석 결과를 시각화합니다.
import plotly.express as px /// plotly 불러오는 방법
#plotly line data 불러오는 방법
fig = px.line(data_frame=your_dataframe, x="x_column_name", y="y_column_name")
fig.show()
///주의할점이 dataframe이 아니라 data_frame 인거 체크하기
# 1. title(영화 제목)별로 revenue(수익)를 그룹화하여 합계를 계산하고, 결과를 데이터프레임 형태로 정리
top = data.groupby('title')['revenue'].sum().reset_index()
/// .sum()이 아니라 mean() 도 가능함
# 2. 수익 기준으로 내림차순 정렬해서 가장 수익이 높은 순서대로 정렬
top = top.sort_values('revenue', ascending=False)
# 3. 상위 10개의 영화만 추출 (흥행 수익 TOP 10)
top = top.head(10)
# 4. Plotly의 bar 차트 생성
fig = px.bar(
data_frame=top, # 시각화에 사용할 데이터프레임
x='title', # x축에는 영화 제목을 표시
y='revenue', # y축에는 영화 수익을 표시
title="흥행 수익 TOP 10 영화", # 차트 제목
color_discrete_sequence=['#C7CEEA'] # 막대 색상 지정 (연보라색 계열)
)
# 5. 그래프 출력 (Jupyter Notebook에서는 자동으로 웹 뷰어가 열림)
fig.show()
💡 보너스 팁
groupby().sum()은 그룹별 합계를 낼 때 자주 쓰이는 대표적인 집계 함수입니다.
reset_index()를 써야 결과가 일반적인 데이터프레임 형태로 바뀌고, 이후 시각화에 쉽게 쓸 수 있어요.
sort_values()로 정렬하면 막대가 높은 순서로 나와서 가독성이 좋아집니다.
color_discrete_sequence는 색을 직접 지정할 수 있는 옵션이며, 리스트 형태로 전달합니다. (색 여러 개 넣으면 범례에 따라 다르게 색칠돼요)
plotly.express는 인터랙티브한 시각화를 손쉽게 만들 수 있어서 matplotlib보다 보기 좋은 결과물이 나오는 경우가 많아요.
title_dic = {'budget':'예산', 'vote_count':'투표수'} # 컬럼명을 한글로 매핑한 딕셔너리
# 'budget'(예산), 'vote_count'(투표수)를 기준으로 각각 TOP10 막대그래프를 그릴 거예요
for y in ['budget', 'vote_count']:
# 1. 'title' 기준으로 그룹화 후, 해당 컬럼(y)의 합계를 구함
# 2. 인덱스를 초기화해 데이터프레임 형태로 만들고
# 3. y 값 기준 내림차순 정렬 후 상위 10개 항목 추출
top = data.groupby('title')[[y]].sum().reset_index().sort_values(y, ascending=False).head(10)
# 4. plotly로 막대그래프 생성
fig = px.bar(
data_frame=top, # 그래프에 쓸 데이터프레임
x='title', # x축에는 영화 제목
y=y, # y축에는 현재 반복 중인 항목 (예산 or 투표수)
title=f"{title_dic[y]} TOP 10 영화", # 제목은 딕셔너리에서 가져온 한글로 표시
color_discrete_sequence=['#AFCBFF'] # 막대 색상 지정 (연한 파란색 계열)
)
# 5. 그래프 출력
fig.show()
top_director =
data # 원본 데이터프레임
.groupby(['director']) # 감독(director)별로 그룹을 짓고
['revenue'].sum() # 각 감독의 총 흥행 수익을 합산한 뒤
.reset_index() # 결과를 표 형태로 보기 좋게 인덱스 초기화하고
.sort_values('revenue', ascending=False) # 수익 기준으로 내림차순 정렬해서
.head(10) # 상위 10명의 감독만 추출해서
#plotly에서 boxplot 만드는 방법
fig = px.box(data_frame = data, y = '', x = 'revenue', hover_name = '')
#data_frame = 데이터 넣고 , y='',x = '' , hover_name='title'
fig.show()
#누적막대그래프
fig = px.bar(data_frame= 하고자하는 데이터, x="", y="", color='main_genre', color_discrete_sequence=px.colors.qualitative.Light24_r)
fig.show()
pd.pivot_table(data=data.query('조건'), index='', columns=' ', values=' ', aggfunc=sum, fill_value=0, margins=True)
pd.pivot_table(
data=data.query('조건'), # 1. 피벗테이블을 만들 데이터, 조건에 맞는 행만 선택
index='', # 2. 행 인덱스로 사용할 컬럼명 (피벗테이블의 행 기준)
columns=' ', # 3. 열로 펼칠 컬럼명 (피벗테이블의 열 기준)
values=' ', # 4. 집계할 값이 들어있는 컬럼명
aggfunc=sum, # 5. 값을 집계할 함수 (예: sum, mean, count 등)
fill_value=0, # 6. 결측값(NaN)을 0으로 채움
margins=True # 7. 행과 열의 합계(총합)를 추가해줌 (전체 합계)
)
위치설명예시
data= | 피벗테이블 만들 대상 데이터프레임, 필요한 행만 걸러서 사용 | data.query('year==2023') |
index= | 피벗테이블에서 행 방향 기준이 될 컬럼명 | 'director', 'region' |
columns= | 피벗테이블에서 열 방향으로 펼칠 컬럼명 | 'genre', 'month' |
values= | 집계하려는 대상 컬럼명 (숫자 데이터) | 'revenue', 'sales' |
aggfunc= | 집계함수, 값을 어떻게 요약할지 정함 | sum, mean, count |
fill_value= | 집계 결과에 결측값이 있을 때 대신 채워줄 값 | 0 (결측값을 0으로 처리) |
margins= | 행과 열의 합계(총합)를 포함할지 여부 (True/False) | True |
#분석에 사용할 컬럼들 불러오고 .corr() 하면 상관관계가 분석됨
data[['col1','col2','col3','col4']].corr()
#상관분석 결과를 시각화한 히트맵
fig = px.imshow(data[['col1','col2','col3','col4']].corr(), text_auto='.2f', color_continuous_scale='Purp')
fig.show()
# text_auto='.2f 소수점 둘째자리까지
#대각선은 자기자신과의 상관관계로 1로 나오는거임
#trendline이 포함된 scatterplot
for x in ['col1', 'col2', 'col3']: # 1. col1, col2, col3 각각을 x축 변수로 사용해서 반복
fig = px.scatter( # 2. 산점도 그래프 생성
data_frame=data, # 3. 그래프에 사용할 데이터프레임 지정
x=x, # 4. x축 값으로 현재 반복 중인 col1, col2, col3 중 하나
y='col4', # 5. y축 값은 col4
hover_name='title', # 6. 점 위에 마우스 올리면 title 컬럼 값이 보임
size='col4', # 7. 점 크기를 col4 값에 비례해서 조절
color='revenue', # 8. 점 색깔을 revenue 값에 따라 다르게 표현
color_continuous_scale=px.colors.sequential.Sunsetdark, # 9. 점 색깔은 어두운 선셋 색상 그라데이션
width=700, # 10. 그래프 가로 크기 700 픽셀
height=600, # 11. 그래프 세로 크기 600 픽셀
trendline='ols' # 12. x, y 데이터에 대해 선형 회귀 추세선을 그림
)
fig.show() # 13. 그래프 화면에 표시
#bubble chart
data = data.sort_values('col1', ascending=False).head( )
# 'col1' 기준으로 내림차순 정렬 후 상위 일부 행만 선택 (head() 안에 숫자 넣으면 그 개수만큼 가져옴
fig = px.scatter(
data_frame=data, # 2. 그래프에 사용할 데이터프레임 지정
x=' ', # 3. x축에 사용할 컬럼명 (여기에 실제 컬럼명 넣어야 함)
y=' ', # 4. y축에 사용할 컬럼명 (여기에 실제 컬럼명 넣어야 함)
hover_name='title', # 5. 마우스 올리면 영화 제목(title) 보여줌
size='col1', # 6. 버블 크기는 'col1' 값에 비례
color='main_genre', # 7. 버블 색상은 'main_genre'별로 구분
color_discrete_sequence=px.colors.qualitative.Light24, # 8. 색상 팔레트는 Light24로 지정
width=700, # 9. 그래프 가로 크기 700픽셀
height=600 # 10. 그래프 세로 크기 600픽셀
)
fig.show()
🎨 그래프 색상 정리
top = data.groupby('title')['revenue'].sum().reset_index().sort_values('revenue', ascending=False).head(10)
fig = px.bar(
data_frame=top,
x='title',
y='revenue',
title="흥행 수익 TOP 10 영화",
color_discrete_sequence=['#C7CEEA'] # 막대 색상
)
# 배경색 설정은 따로!
fig.update_layout(
paper_bgcolor='white', # 전체 배경
plot_bgcolor='white', # 그래프 영역 배경
yaxis=dict(
showgrid=True,
gridcolor='lightgray'
)
)
fig.show()
#그 외의 취향이던 막대 색상
# pastel = ['#FFB5E8', '#FF9CEE', '#B28DFF', '#DCD3FF', '#AFCBFF', '#B5EAD7', '#C7CEEA']
✨ 복습하면서 헷갈리던 것들
✅ 정리:
title_dic = {'budget':'예산', 'vote_count':'투표수'}
딕셔너리를 쓴 이유
이유설명
보기 좋은 한글 제목으로 바꾸기 위해 | plotly title에 사용할 때 직관적 제목을 만들 수 있음 |
반복문에서 조건별 처리할 때 유용 | y 값에 따라 title을 자동으로 다르게 생성 가능 |
향후 컬럼이 늘어나도 확장성 확보 | 딕셔너리만 추가하면 코드 전체 수정 없이 반복 가능 |
🔍 왜 title_dic = {'budget': '예산', 'vote_count': '투표수'}처럼 딕셔너리로 묶었을까?
✅ 1. 반복문에서 컬럼명을 바꿔서 출력하기 위함
- for y in ['budget', 'vote_count']: 이렇게 반복하면서
- 그래프 title에 한글 제목을 넣고 싶잖아요?
그래서 아래처럼 쓸 수 있게 만든 거예요:
title=f"{title_dic[y]} TOP 10 영화"
# y가 'budget'이면 → "예산 TOP 10 영화"
# y가 'vote_count'면 → "투표수 TOP 10 영화"
✅ groupby()는 언제 사용하나요?
groupby()는 데이터를 특정 기준(컬럼 값)에 따라 묶고, 묶인 각 그룹에 대해 합계, 평균, 개수 등의 집계(aggregation) 연산을 하고 싶을 때 사용합니다.
✅ 요약
함수역할
groupby() | 특정 기준으로 그룹 묶기 + 집계 연산 |
reset_index() | 그룹 결과의 인덱스를 일반 컬럼으로 변환해서 보기 좋게 만들기 |
///Q : dropna()함수로 결측치 제거하는데 inplace=True는 왜 사용해? 이게 무슨의미야?
data.dropna(inplace=True)
///✅ inplace=True의 의미
///"결측치를 제거한 결과를 원본 데이터프레임 data에 바로 반영해줘!" 라는 뜻입니다.
✅ inplace=True의 장단점
🔹 장점
- 메모리 효율성
- 새로운 복사본을 만들지 않아서 메모리 사용량이 적어요.
- 특히 데이터가 매우 클 때 유리해요.
- 코드 간결
- 별도의 변수 없이 한 줄로 처리할 수 있어서 깔끔해 보여요.
🔸 단점
- 원본 데이터가 바뀜
- 한 번 바뀌면 되돌리기 어렵거나 불가능해요 (undo 불가).
- 실수로 중요한 데이터를 날릴 위험이 있음.
- 코드의 가독성과 추적성 감소
- df = df.dropna()처럼 할당하는 방식은 변화를 명확하게 보여줌.
- inplace=True는 묵시적으로 변경되므로 디버깅이나 추적이 어려울 수 있어요.
- 일부 함수에서는 inplace 옵션이 없어졌거나 사라질 예정
- 최신 판다스 버전에서는 inplace=True가 비추천(deprecated) 되는 방향으로 가고 있어요.
🚀 처음 보는 함수 정리
ast.literal_eval()은 문자열(String)을 실제 파이썬 객체처럼 안전하게 변환해주는 함수예요.
보통 문자열로 저장된 리스트나 딕셔너리 등을 진짜 리스트나 딕셔너리 객체로 바꿀 때 사용합니다.
import ast
result = ast.literal_eval('[1, 2, 3]')
print(result) # [1, 2, 3]
print(type(result)) # <class 'list'>
📌 언제 쓰나?
- CSV, Excel, JSON 등에서 "[1, 2, 3]", "{'a': 1}" 같은 문자열 형태의 자료구조가 저장되어 있을 때,
- eval() 대신 안전하게 문자열을 파싱하고 싶을 때 사용합니다
ast.literal_eval("{'name': 'Alice', 'age': 25}")
# => {'name': 'Alice', 'age': 25}
ast.literal_eval("('x', 1, True)")
# => ('x', 1, True)