| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | |
| 7 | 8 | 9 | 10 | 11 | 12 | 13 |
| 14 | 15 | 16 | 17 | 18 | 19 | 20 |
| 21 | 22 | 23 | 24 | 25 | 26 | 27 |
| 28 | 29 | 30 | 31 |
- HTML
- 코딩테스트준비
- node.js
- 99클럽
- 개발자취업
- 파이썬프로그래밍기초
- 데이터베이스시스템
- 중간이들
- Python
- JavaScript
- 오픈소스기반데이터분석
- Git
- 항해99
- 코드잇
- mongoDB
- aws
- 방송대
- nestjs
- 꿀단집
- 방송대컴퓨터과학과
- TiL
- Azure
- redis
- 코딩테스트
- CSS
- 프로그래머스
- 파이썬
- 클라우드컴퓨팅
- 엘리스sw트랙
- 유노코딩
- Today
- Total
배꼽파지 않도록 잘 개발해요
[코드잇] 데이터 사이언스 기초 - 데이터 분석과 시각화 본문

1. 시각화와 그래프
시각화의 두 가지 목적
| 1. 시각화는 분석에 도움을 줌. | 2. 리포팅에 도움이 된다. |
| · 그래프는 패턴을 발견하기 쉬워서 의사결정에 도움이 됨. · 시각화를 하면 보이지 않는 문제들이 보이기 시작함. ex. 데이터 하나만 동떨어져 있는 경우(이상점, outlier) → 심층 분석 |
· 리포팅 : 데이터에 대해 보고하는 것 · 숫자 정보만 있으면 직관적으로 이해가 되지 않음. · 예뻐서 집중해서 쳐다보므로 커뮤니케이션에 도움이 됨. |
선그래프
x축에는 보통 시간과 관련된 값이 들어감.
문자에 대해서 그래프를 그리려고 하면 오류가 발생함.
%matplotlib inline
import pandas as pd
df = pd.read_csv(r'C:\Users\airyt\Downloads/sports.csv', index_col=0)
df.plot()
df.plot(kind='line') # 선그래프가 기본이기 때문에 파라미터는 생략해도 됨.
df.plot(y='KBS') # KBS에 대한 선 '하나만' 나옴
df.plot(y=[ 'KBS', 'JTBC' ]) # 원소가 여러개일 경우는 리스트로 넘겨주기
# df불러오고 .plot() 메소드 이용
df[['KBS', 'JTBC']].plot() # 여러 개의 df
df['KBS'].plot() # 한 개의 df
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
막대 그래프
카테고리 비교를 위해 사용함.
df.plot() # 기본 설정이 선그래프임.
df.plot(kind='bar') # 막대그래프가 나옴.
df.plot(kind='barh') # h = horizontal의 약자
df.plot(kind='bar', stacked=True) # 막대가 쌓여서 나옴 → 총계가 한눈에 보임
df['Female'].plot(kind='bar') # 여성에 대한 그래프만 나옴.
![]() |
![]() |
![]() |
![]() |
그래프 그리기
%matplotlib inline
import pandas as pd
df = pd.read_csv('data/silicon_valley_summary.csv')
# 각 조건을 변수 A, B, C에 불린값으로 저장
A = (df['job_category'] == 'Managers')
B = (df['gender'] == 'Male')
C = (df['race_ethnicity'] != 'All')
# 불린값을 넣어주어 조건에 맞는 데이터 추출 → 그래프 그리기
df[A & B & C].plot(kind='bar', x='race_ethnicity', y='count')
'''
df.loc[A & B & C].plot(kind='bar', x='race_ethnicity', y='count')
→ 결과가 동일하게 나온다
'''
Pandas 리스트로 인덱싱할 때 문제점
%matplotlib inline
import pandas as pd
df = pd.read_csv('data/silicon_valley_summary.csv', index_col=1)
# 인덱스(행)에서 'All'부분은 제외
f_df = df[ df.index != 'All']
# 원하는 조건의 데이터만 추출 (managers, male, 그래프: count, race_ethnicity)
c = f_df.loc[ (f_df['job_category'] == 'Managers') & ( f_df['gender'] == 'Male'),
['count', 'race_ethnicity']]
# 그래프 그리기
c.plot(kind='bar', x='race_ethnicity', y='count') # x축 지정 안 해줘도 나오긴 함.

오류나는 코드
%matplotlib inline
import pandas as pd
df = pd.read_csv('data/silicon_valley_summary.csv'. index_col=1)
d_manager = (df['job_category'] == 'Managers')
d_male = (df['gender'] == 'Male')
d_except = (df.index != 'All')
df[d_manager & d_male & d_except].plot(kind='bar', x='race_ethnicity', y='count')
# 이미 index로 race_ethnicity column이 지정되어서
# 마지막에 x축으로 race_ethnicity를 지정할 때 에러가 발생함.
파이 그래프
절대적인 수치보다 비율을 표현하기에 좋음.
ex. 선거 결과 : 몇 표(수치) < 몇 퍼센트 (비중)
df.loc[2017].plot(kind='pie') # 파이 그래프 출력
![]() |
![]() |
%matplotlib inline
import pandas as pd
df = pd.read_csv('data/silicon_valley_details.csv')
# 불린값을 변수에 저장
A = df['company'] == 'Adobe'
B = df['count'] != 0
C = df['job_category'] != 'Totals'
D = df['job_category'] != 'Previous_totals'
E = df['race'] == 'Overall_totals'
# 원하는 데이터프레임 출력
n_df = df[ A & B & C & D & E ][['job_category', 'count']]
# 인덱스 변경 (파이 그래프 그리기 위해)
n_df.set_index('job_category', inplace=True)
# 파이그래프 그리기 (y값도 지정해줘야 함)
n_df.plot(kind='pie', y='count')
| df[ A & B & C & D & E ][['job_category', 'count']] | n_df = df[ A & B & C & D & E ][['job_category', 'count']] n_df.set_index('job_category', inplace=True) |
![]() |
![]() |
파이 그래프는 index를 기준으로 이름표를 달아줌,
set_index(keys, inplace=True)로 인덱스 변경해야함.
히스토그램
1,000명의 학생을 대상으로 키를 조사함.
· 막대그래프 : 항목비교, 키(항목)이 너무 많아짐.
· 파이그래프 : 차지하는 비율, 키(항목)이 너무 많아짐.
→ 히스토그램 사용
• 히스토그램에서는 키를 각각의 항목으로 두는 것이 아니라 범위로 묶어서 봄.
• 대략적인 값들의 분포를 한번에 알 수 있음.
df.plot(kind='hist', y='Height') # 보고 싶은 컬럼 = y축
df.plot(kind='hist', y='Height', bins=20)
# bins: 히스토그램의 가로축 구간의 개수 → 막대기가 20개
# 상황에 맞는 적당한 숫자 찾기
![]() |
![]() |
박스 플롯
데이터 정보에 대한 통계 정보를 시각적으로 보여주기 위해 사용됨.
총 5개의 통계값으로 데이터 셋을 요약함.

# 통계 수치 요약
df['math score'].describe()
# 한 항목에 대한 박스 플롯 생성
df.plot(kind='box', y='math score')
# 여러 항목에 대한 박스 플롯 생성
df.plot(kind='box', y=['math score', 'reading score', 'writing score'])
# 위스커(상위25%, 하위25%)가 길다 = 해당 구간은 점수가 분산되어 있다
![]() |
|
![]() |
![]() |
산점도(scatter plot)
상관관계를 보여주기 적합함.
ex. 행복지수와 등수, 몸무게와 키 등이 서로 연관이 있는지
모양을 보고 연관성을 찾을 수 있음.
df.plot(kind='scatter', x='reading score', y='writing score')
![]() |
|
![]() |
![]() |
2. Seaborn 시각화
Seaborn
Statistical Data Visualization (통계를 기반으로 한 데이터 시각화)
pandas보다 더 다양하고 근사한 그래프를 그릴 수 있음.
seaborn: statistical data visualization — seaborn 0.12.2 documentation
seaborn: statistical data visualization
seaborn.pydata.org
확률 밀도 함수 (PDF)
Probability Density Function
데이터셋의 분포를 나타냄. (히스토그램의 막대수를 무한으로 늘리면 거의 비슷해짐.)
특정 구간의 확률은 그래프 아래 그 구간의 면적과 동일함.
그래프 아래의 모든 면적을 더하면 1임.
특정 값에 대한 확률 구하기 (X), 특정 범위에 대한 확률 (O)
KDE Plot
# seaborn 설치
!pip install seaborn == 0.9.0
# 각 키가 몇 번 나오는지 빈도 출력
body_df['height'].value_counts()
# 인덱스 순으로 정렬 → .sort_index()
body_df['height'].value_counts().sort_index()
# 그래프 그리기 → .plot()
body_df['height'].value_counts().sort_index().plot()
# seaborn 라이브러리의 kedplot 사용 → sns.kdeplot()
sns.kdeplot(body_df['height'])
# bw 파라미터
'''
seaborn으로 그린 그래프는 실제 데이터 분포와 다름.
추측을 어느 정도 할지 설정할 수 있음.
seaborn으로 그린 그래프는 "bw 파라미터" 사용
bw가 "작을수록" 분포 표현을 Histogram과 가깝게 그림
'''
sns.kdeplot(body_df['height'], bw=0.5)
KDE 활용 예시
# 히스토그램
body_df.plot(kind='hist', y='Height', bins=15)
# 히스토그램 위에 KDE 곡선이 그려짐
sns.distplot(body_df['Height'], bins=15)
# 박스 플롯 : 통계 요약본 느낌
body_df.plot(kind='box', y='Height')
# 바이올린 플롯 : 분포 전체를 볼 수 있음.
sns.violinplot(y=body_df['Height'])
# 키와 몸무게의 연관성 → 산점도
body_df.plot(kind='scatter', x='Height', y='Weight')
# 175cm 70kg 학생들이 많이 분포함.
# 키가 클수록 몸무게가 많이 나가는 경향이 있음.
# 등고선 : 높낮이 표현
sns.kdeplot(body_df['Height'], body_df['Weight'])
# x축 : 키에 대한 KDE
# y축 : 몸무게에 대한 KDE
# 3차원으로 생성, 간격이 멀수록 평평, 가까울수록 가파름.
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
LM Plot
sns.lmplot(data=body_df, x='Height', y='Weight')
'''
◆ 회귀선(regression line) : 흩어져 있는 점들을 하나로 표현
키 175cm인 학생은 몸무게 72kg정도 될 것 같다
키와 몸무게의 연관성이 매우 뚜렷하지 않아서 모든 점들이 이 선을 다 지나가지 않음.
'''

pip install --upgrade numpy # numpy 버전 업그레이드
pip install --upgrade seaborn # seaborn 버전 업그레이드
→ 둘 다 최신버전으로 업데이트해서 호환성 문제 발생하지 않도록 하면 오류 해결 가능
카테고리별 시각화
# box
sns.catplot(data=laptops_df, x='os', y='price', kind='box')
# strip
sns.catplot(data=laptops_df, x='os', y='price', kind='strip')
# hue : 색 (브랜드에 따라 색을 다르게 해줌)
sns.catplot(data=laptops_df, x='os', y='price', kind='strip', hue='processor_brand')
# swarm
sns.catplot(data=laptops_df, x='os', y='price', kind='swarm', hue='processor_brand')
# x축의 os 순서 바꾸기 (order 지정)
sns.catplot(data=laptops_df, x='os', y='price', kind='swarm', hue='processor_brand',
order=['mac', 'linux', 'window'])
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
3. 통계 기본 상식
평균값과 중간값
| 평균값(Mean) | 중간값(Median) |
| 데이터들의 합 / 데이터 개수 잘못된 데이터, 이상값의 영향을 크게 받음. |
주어진 값들을 크기순으로 정렬하였을 때 가장 중앙에 위치하는 값 • 홀수 개수 : 가운데 • 짝수 개수 : 가운데 2개의 평균 잘못된 데이터, 이상값의 영향을 덜 받음. |
Q1, Q3구하기
| Q1 | Q3 |
| Q1이 몇 번 인덱스에 있는 값인지 구하기 : (8−1)∗0.25 · 특정 퍼센트 지점 인덱스 : (데이터 개수 - 1) x 숫자 (인덱스가 0부터 시작하니까) |
Q3이 몇 번 인덱스인지 구하기 : (8−1)∗0.75 |
| 만약 인덱스가 1.75인 경우 : 15(인덱스 1) 20(인덱스2) 사이의 0.75(4분의 3) 15 * (1-0.75) + 20 * 0.75 |
만약 인덱스가 5.25인 경우 : 57(인덱스 1) 63(인덱스2) 사이의 0.25(4분의 1) 57 * (1-0.25) + 63 * 0.25 |
이상값 구하기
IQR(Interquartile Range) = Q3 - Q1
아래로 1.5 IQR 더 떨어져 있거나, Q3 지점에서 위로 1.5 IQR 더 떨어져 있는 값
ex. Q3(58.5) - Q1(18.75) = 39.75 (-40.875와 118.125 사이의 바깥에 있는 값이 이상값)

# 평균값
import math
list = [5, 48, 17, 62, 33, 18, 22]
mean = sum(list) / len(list)
print(mean)
# 중앙값
import math
list = [5, 48, 17, 62, 33, 18, 22]
A = (len(list) - 1) / 2
if len(list) % 2 == 0: # 짝수
B = (list[math.floor(A)] + list[math.ceil(A)]) / 2
print(B)
else : # 홀수
C = list[math.floor(A)]
print(C)
list = [5, 48, 17, 62, 33, 18, 22]
s_list = sorted(list)
# [5, 17, 18, 22, 33, 48, 62]
'''
데이터 개수 : len(list) # 7
특정 지점 인덱스 : (len(list)-1) * 숫자
'''
# Q1과 Q3
index_Q1 = (len(s_list)-1) * 0.25 # 1.5
Q1 = s_list[1] * (1-0.25) + s_list[2] * 0.25 # 17.25
index_Q3 = (len(s_list)-1) * 0.75 # 4.5
Q3 = s_list[4] * (1-0.75) + s_list[5] * 0.75 # 44.25
# 이상값
IQR = Q3 - Q1 # 27.0
'''
(Q1 - 1.5 * IQR) <= num <= (Q3 + 1.5 * IQR)
-23.25 <= num <= 84.75
'''
outlier = []
# 이상값을 찾는 코드
for num in s_list:
if not (Q1 - 1.5 * IQR) <= num <= (Q3 + 1.5 * IQR):
outlier.append(num)
# 이상값이 있을 때만 출력
if outlier:
print("이상값은 {}입니다.".format(outlier))
else:
print("이상값이 없습니다.")
'''
이상값이 없습니다.
'''
'''
같은 리스트에서 100, 13000을 추가
'''
list = [5, 48, 17, 62, 33, 18, 22, 100, 13000]
s_list = sorted(list)
# [5, 17, 18, 22, 33, 48, 62]
'''
데이터 개수 : len(list) # 7
특정 지점 인덱스 : (len(list)-1) * 숫자
'''
# Q1과 Q3
index_Q1 = (len(s_list)-1) * 0.25 # 1.5
Q1 = s_list[1] * (1-0.25) + s_list[2] * 0.25 # 17.25
index_Q3 = (len(s_list)-1) * 0.75 # 4.5
Q3 = s_list[4] * (1-0.75) + s_list[5] * 0.75 # 44.25
# 이상값
IQR = Q3 - Q1 # 27.0
'''
(Q1 - 1.5 * IQR) <= num <= (Q3 + 1.5 * IQR)
-23.25 <= num <= 84.75
'''
outlier = []
# 이상값을 찾는 코드
for num in s_list:
if not (Q1 - 1.5 * IQR) <= num <= (Q3 + 1.5 * IQR):
outlier.append(num)
# 이상값이 있을 때만 출력
if outlier:
print("이상값은 {}입니다.".format(outlier))
else:
print("이상값이 없습니다.")
'''
이상값은 [100, 13000]입니다.
'''
상관 계수 (Correlation Coefficient)
데이터에서 두 변수가 얼마나 연관성이 있는지 보여주는 값
Pearson 상관 계수
| 0 | x와 y는 연관이 없다 |
| 1 | x와 y는 확실한 연관이 있다 |
| -1 | x와 y는 확실한 연관(x가 커질수록 y가 작아짐)이 있다 |
상관계수 시각화
# 숫자 데이터 사이의 상관 계수
df.corr()
# 히트맵 (상관계수의 시각화)
sns.heatmap(df.corr())
# annot은 숫자 표기되게끔 함
sns.heatmap(df.corr(), annot=True)
![]() |
![]() |
![]() |
4. Exploratory Data Analysis
탐색적 데이터 분석 (EDA)
Exploratory Data Analysis
데이터셋을 다양한 관점에서 살펴보고 탐색하면서 인사이트를 찾는 것
ex.
각 row는 무엇을 의미하는가
각 column은 무엇을 의미하는가
각 column은 어떤 분포를 보이는가
두 column은 어떤 연관성이 있는가
설문조사 결과 EDA
기본정보 파악 : 참여인원, 연령대, 성별, 최종 학력, 가족관계, 관심사 등
시각적인 방법, 통계적인 방법
기본 정보 파악하기
# 기본 정보가 있는 column
basic_info = df.iloc[:, 140:]
basic_info.head()
basic_info.describe()
basic_info['Gender'].value_counts()
basic_info['Handedness'].value_counts()
basic_info['Education'].value_counts()
# 나이 분포
sns.violinplot(data=basic_info, y='age')
# 10대~20대후반이 많음.
# 성별에 따른 나이분포
sns.violinplot(data=basic_info, x='Gender', y='Age')
# 성별에 따른 나이분포와 왼손/오른손잡이 유무
sns.violinplot(data=basic_info, x='Gender', y='Age', hue='Handedness')
# 키와 몸무게의 연관성 & 히스토그램 (jointplot)
sns.jointplot(data=basic_info, x='Height', y='Weight')
![]() |
![]() |
![]() |
![]() |
상관 관계 분석 (Correlation Analysis)
'''
좋아하면 5점, 안 좋아하면 1점
음악 관련된 부분만 추출
처음부터 19번째 열까지 음악과 관련됨
'''
# 데이터 추출
music = df.iloc[:, :19]
music.head()
# 히트맵 그리기
sns.heatmap(music.corr())
'''
연한색 = 연관성 ↑
진한색 = 연관성 ↓
오페라와 힙합 : 검정색
오페라를 좋아하는 사람이 힙합을 덜 좋아할 것 같음.
오페라와 클래식 : 주황색
오페라를 좋아하는 사람이 클래식을 좋아할 것 같음.
팝, 힙합, 테크노 장르들이 댄스와 큰 연관성이 있음.
'''
# 상관관계 중 나이에 관한 것만 출력해서 정렬
df.corr()['Age'].sort_values(ascending=False)
# -> 나이와 상관관계가 높은 것과 낮은 것을 확인할 수 있음
![]() |
![]() |

import pandas as pd
# 모든 행과 열을 표시하도록 설정
pd.set_option('display.max_rows', None) # 행
pd.set_option('display.max_columns', None) # 열
# 설정 초기화
pd.reset_option('display.max_rows') # 행
pd.reset_option('display.max_columns') # 열
# 특정 column이 몇 번째 인덱스에 있는지 알고 싶으면
df.columns.get_loc(' ')
# 데이터프레임의 모든 열 목록 출력
df.columns
# type : pandas.core.indexes.base.Index
# 모든 열 이름을 리스트로 만들어서 출력
df.columns.tolist()
# type : list
# --> 중간에 생략된 부분 있어서 리스트로 출력하니까 보임

%matplotlib inline
import pandas as pd
import seaborn as sns
df = pd.read_csv(r'C:\Users\airyt\Downloads/young_survey.csv')
# 1부터 18 인덱스에 해당하는 열 출력
df.iloc[:, 1:19].corr()['Getting up'].sort_values(ascending=False)
'''
오류나는 이유
df.iloc[:, 1:19] 부분은 1부터 18번째 열을 선택하는데,
이 범위에 'Getting up' 열이 포함되어 있지 않기 때문에 오류가 발생
'''

'''
1. 데이터를 음악장르 + Getting up으로 추림
2. Getting up과 관련된 부분만 상관관계 출력
'''
music_df = df.iloc[:, [i for i in range(19)] + [128]]
music_df.corr()['Getting up'].sort_values(ascending=True)
# --> 이렇게 굳이 할 필요 없음
'''
Getting up 열의 상관관계 분석 중 1번부터 18번째 열만 출력
'''
df.corr()['Getting up'][1:19].sort_values(ascending=True)
주의할 점은 5점이 일찍 일어나기 힘듦, 1점이 일어나기 쉬움임.
일찍 일어나는 사람들이 가장 좋아하는 음악 장르를 물어본다면,
상관계수가 음수인 것중에 절대값이 큰 걸 골라야 함. (반대)
![]() |
![]() |
# 특정 컬럼의 인덱스 값 가져오기
df.columns.get_loc()
index = df.columns.get_loc('Getting up') # (대괄호 없이 이름만)
print(index) # 128
'''
get_loc()는 단일 열 이름에 대한 위치를 반환함.
df.columns.get_loc(['Getting up', 'Dance']) ---> 에러 발생
'''
# 여러 컬럼의 인덱스 값 가져오기
# get_loc() 안에 for 반복문으로 컬럼 하나씩만 가지고 와야됨
columns_to_find = ['Getting up', 'Dance']
indices = [df.columns.get_loc(c) for c in columns_to_find]
print(indices) # [128, 2]
# 열 이름과 위치(인덱스) 동시에 출력
print("열 위치")
for col, index in zip(columns_to_find, indices):
print(f'{col}:{index}')
'''
열 위치
Branded clothing:135
Healthy eating:75
'''
클러스터 분석(Cluster Analysis)
클러스터 = 뭉쳐있는 무리
데이터를 몇 가지 부류로 나누는 것 (ex. 학생들 = 이과, 문과, 예체능)
# 사내 동아리 만드려고 하는데, 관심사 비슷한 사람들끼리 모을 것임
df = pd.read_csv(r'C:\Users\airyt\Downloads/young_survey.csv')
df.head()
# 관심사 간 상관관계 구하기
# 관심사가 있는 컬럼 : 'History'부터 'Pets'까지
interests = df.loc[:, 'History':'Pets']
c = interests.corr()
# 역사 좋아하는 사람들만 따로 뽑아보기 (내림차순)
c['History'].sort_values(ascending=False)
# 정치, 지리, 법 등을 좋아하는 사람들과 묶을 수 있음
# ---> 한 컬럼씩 일일히 다 하기 어려움
# 연관성 있는 관심사끼리 묶어 놓은 것
sns.clustermap(corr)
# 묶여 있는 것들 : ex. 연극, 미술전시, 독서, 심리 등
![]() |
![]() |
c = df.loc[:, 'Horror':'Action'].corr().sort_values(ascending=False)
# 또는 c = df.loc[:, 'Horror':'Action'].sort_values(ascending=False).corr()
sns.clustermap(c) # 오류
# sort_values가 데이터프레임 전체를 정렬하기 때문에 오류가 남.
# 아래와 같은 방법을 고려할 수 있음.
# 상관계수 행렬을 series로 변환하고 정렬
sorted_corr = c.unstack.sorted_values(ascending=False)
# 데이터프레임에서 빈 값 확인
df.isna()
# 또는
df.isnull()
# 'Horror'열에 빈값 있는지 확인하기
df['Horror'].isna()
![]() |
![]() |
타이타닉 EDA
1. 타이타닉의 승객은 30대와 40대가 가장 많다.
# 타이타닉의 승객은 30대와 40대가 가장 많다. (X)
print(df[df['Age'] < 10]['Age'].count()) # 10세 미만의 승객 수 출력 : 62
print(df[(10 <= df['Age']) & (df['Age'] < 20)]['Age'].count()) # 10대 승객 수 출력 : 102
print(df[(20 <= df['Age']) & (df['Age'] < 30)]['Age'].count()) # 20대 승객 수 출력 : 220
print(df[(30 <= df['Age']) & (df['Age'] < 40)]['Age'].count()) # 30대 승객 수 출력 : 167
print(df[(40 <= df['Age']) & (df['Age'] < 50)]['Age'].count()) # 40대 승객 수 출력 : 89
print(df[(50 <= df['Age']) & (df['Age'] < 60)]['Age'].count()) # 50대 승객 수 출력 : 48
print(df[60 <= df['Age']]['Age'].count()) # 60세 이상 승객 수 출력 : 26
# 히스토그램으로 보는 나이 분포
df.plot(kind='hist', y='Age', bins=30)



2. 가장 높은 요금을 낸 사람은 30대이다.
# 가장 높은 요금을 낸 사람은 30대이다. (O)
df[df['Fare'] == df['Fare'].max()]
# 나이와 요금 사이를 산점도로 표현
df.plot(kind='scatter', x='Age', y='Fare')

3. 생존자가 사망자보다 더 많다.
# 생존자가 사망자보다 더 많다. (X)
# survived 컬럼에서 0과 1의 개수
df['Survived'].value_counts()
# 0 (사망): 549, 1:(생존) 342

4. 1등실, 2등실, 3등실 중 가장 많은 사람이 탑승한 곳은 3등실이다.
# 1등실, 2등실, 3등실 중 가장 많은 사람이 탑승한 곳은 3등실이다. (O)
df['Pclass'].value_counts()
'''
3 491
1 216
2 184
'''

5. 가장 생존율이 높은 객실 등급은 1등실이다.
# 가장 생존율이 높은 객실 등급은 1등실이다. (O)
df.groupby('Pclass')['Survived'].value_counts()
# ---> 2, 3등실은 사망이 더 많음.
result = df.groupby(['Pclass', 'Survived']).size().unstack().fillna(0)
result = result[[1, 0]]
result['survival rate'] = result[1] / (result[0] + result[1]) * 100
result
# size() : 'Pclass'와 'Survived' 열을 기준으로 데이터를 그룹화한 후, 각 그룹의 크기를 계산하여 result에 저장
# unstack() : 그 결과를 메서드로 표 형태로 변환함.
# fillna() : 빈 값을 0으로 채움.
# result[[1,0]] : 결과를 1과 0 순서로 재정렬


# 객실 등급별 생존율 분포
df.plot(kind='scatter', x='Pclass', y='Survived')
# ---> 일반 산점도는 그림이 겹쳐서 나와서 KDE plot 이용
'''
sns.kdeplot(df['Pclass'], df['Survived'])
이렇게 쓰면 에러남.
TypeError: kdeplot() takes from 0 to 1 positional arguments but 2 were given
'''
sns.kdeplot(x=df['Pclass'], y=df['Survived'])
# ---> 1등급은 위쪽(생존율 높은 쪽)이 더 많이 나옴.


6. 나이가 어릴수록 생존율이 높다.
# 나이가 어릴수록 생존율이 높다. (X)
# 상관관계 분석
df.corr()
# 생존 여부에 따른 나이 분포
sns.violinplot(data=df, x="Survived", y="Age")


생존한 사람들(1)의 나이분포와 사망한 사람의 나이분포(0)가 비슷함.
유의미한 차이가 없어서 단정짓기 힘들다.
7. 나이보다 성별이 생존율에 더 많은 영향을 미친다.
# 나이보다 성별이 생존율에 더 많은 영향을 미친다. (O)
result = df.groupby(['Sex', 'Survived']).size().unstack().fillna(0)
result = result[[1, 0]]
result['survival rate'] = (result[1] / (result[0] + result[1]))* 100
result
# 생존 여부에 따른 나이 및 성별 분포
sns.stripplot(data=df, x="Survived", y="Age", hue="Sex")


살아남은 사람들(Survived=1)의 분포 중 여성의 비율이 압도적으로 높음.
5. 새로운 인사이트 발견하기
새로운 값 계산하기
새로운 컬럼 생성 후 그래프를 만들어서 인사이트 얻을 수도 있음.
%matplotlib inline
import pandas as pd
df = pd.read_csv(r'C:\Users\airyt\Downloads/broadcast.csv', index_col=0)
df
df.plot()
![]() |
![]() |
# 메이저 방송사들을 합찬 시청률
# df['KBS'] + df['MBC'] + df['SBS'] + df['TV CHOSUN'] + df['JTBC'] + df['Channerl A'] + df['MBN']
df.sum(axis='columns')
df['Total'] = df.sum(axis='columns')
df
df.plot(y='Total')
# TV 시청률이 해가 갈수록 떨어짐
![]() |
|
![]() |
![]() |
# 지상파 vs 종편 시청률 비교
# 지상파 : df['KBS'] + df['MBC'] +df['SBS']
# 종편 : df['TV CHOSUN'] + df['JTBC'] + df['Channel A'] + df['MBN']
# 지상파와 종편을 각각 Group 1'과 'Group 2'으로 생성
df['Group 1'] = df.loc[:, 'KBS':'SBS'].sum(axis='columns') # 지상파
df['Group 2'] = df.loc[:, 'TV CHOSUN':'MBN'].sum(axis='columns') # 종편
# 그래프 그리기
df.plot(y=['Group 1', 'Group 2'])

문자열 필터링
# 모든 장르 파악 (중복제거)
df['Genre'].unique()
# 여기서 장르가 'Blues'인 앨범들만 추출
df['Genre'] == 'Blues'
# 장르에 'Blues'라는 단어가 포함된 앨범들이 추출
df['Genre'].str.contains('Blues')
# 장르에서 'Blues'가 앞에 있는 앨범들만 추출
df[df['Genre'].str.startswith('Blues')]
# 장르에서 'Blues'가 맨 뒤에 있는 앨범들만 추출
df[df['Genre'].str.endswith('Blues')]
이 데이터프레임에서 contains blues라는 컬럼
포함하면 True, 안 그러면 False
df['Contains Blues'] = df['Genre'].str.contains('Blues')
df
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |

### 1번 방법
df['분류'][df['분류'] == False] = '일반'
df['분류'][df['분류'] == True] = '대학'
### 2번 방법
is_university = df['시설명'].str.contains('대학교')
df.loc[is_university == True, '분류'] = '대학'
df.loc[is_university == False, '분류'] = '일반'
문자열 분리
df = pd.read_csv(r'C:\Users\airyt\Downloads/parks.csv', index_col=0)
df['소재지도로명주소']
# 컬럼 출력
df['소재지도로명주소'].str.split()
'''
◆ 띄어쓰기 기반으로 단어를 나누어서 리스트를 생성
관리번호
29170-00001 [광주광역시, 북구, 대천로, 86]
'''
address = df['소재지도로명주소'].str.split(n=1, expand=True)
df['관할구역'] = address[0]
df
'''
◆ n=숫자 --> 숫자번째 띄어쓰기만 가지고 나누어줌
◆ expand=True --> 나눈 것 기준으로 새로운 DF이 출력됨.
관리번호
29170-00001 [광주광역시, 북구 대천로 86]
'''
![]() |
![]() |

number = df['운영기관전화번호'].str.split(pat='-', n=2, expand=True)
number = df['운영기관전화번호'].str.split('-', expand=True)
# → 두 개 결과 똑같이 나옴.
'''
pat='' → 구분 기준 (문자)
n=2 → 최대 2번 분리
expand=True → 결과가 DataFrame으로 보여짐
'''
카테고리로 분류
# 브랜드가 아니라 노트북 제조한 국가별로 분류하고 싶음.
brand_nation = {
'Deli' : 'U.S.',
'Apple' : 'U.S.',
'Acer' : 'Taiwan',
'HP' : 'U.S.',
'Lenovo' : 'China',
'Alienware' : 'U.S.',
'Microsoft' : 'U.S.',
'Asus' : 'Taiwan'
}
'''
df['brand'].map(brand_nation)
# map함수는 key와 item을 서로 바꿔줌.
'''
df['brand_nation'] = df['brand'].map(brand_nation)

![]() |
![]() |
groupby
# brand_nation 열을 기준으로 데이터프레임을 그룹화하여 nation_groups 객체에 저장
nation_groups = df.groupby('brand_nation')
# nation_groups의 타입을 출력 (pandas의 GroupBy 객체)
type(nation_groups)
# 각 그룹별로 데이터의 개수를 세어 반환
nation_groups.count()
# 각 그룹별로 'price' 열의 최대값을 반환
nation_groups.max()
# 각 그룹별로 'price' 열의 평균값을 반환
nation_groups.mean()
# 각 그룹별로 첫 번째 행을 반환
nation_groups.first()
# 각 그룹별로 마지막 행을 반환
nation_groups.last()
# 'price' 열에 대한 상자그림을 그림
nation_groups.plot(kind='box', y='price')
# 'price' 열에 대한 히스토그램을 그림
nation_groups.plot(kind='hist', y='price')
import pandas as pd
data = {'성별': ['남', '여', '남', '여', '남'],
'시험점수': [85, 95, 75, 90, 80]}
df = pd.DataFrame(data)
# groupby('그룹화컬럼')['집계컬럼'].통계함수()
df.groupby('성별')['시험점수'].mean()
# groupby('그룹화컬럼').통계함수()['집계컬럼']
df.groupby('성별').mean()['시험점수']
# [['그룹화컬럼','집계컬럼']].groupby('그룹화컬럼').통계함수()
df[['시험점수', '성별']].groupby('성별').mean()
'''
1. df[['시험점수', '성별']]: 이 부분은 데이터프레임 df에서 '시험점수'와 '성별' 두 열을 선택함.
2. .groupby('성별'): 선택한 열을 '성별' 기준으로 그룹화함. 이는 '성별'이 같은 행들을 하나의 그룹으로 묶음.
3. .mean(): 그룹화된 결과에 대해 각 그룹의 평균을 계산함. 이 경우에는 '시험점수'의 평균을 계산함.
'''
![]() |
![]() |
데이터 합치기
- inner join : 겹치는 것만
- left outer join : 왼쪽 데이터프레임에 있는 것만
- right outer join : 오른쪽 데이터프레임에 있는 것만
- full outer join : 양쪽에 있는 모든 걸 합침
# inner join
pd.merge(price_df, quantity_df, on='Product')
# left join
pd.merge(price_df, quantity_df, on='Product', how='left')
# right join
pd.merge(price_df, quantity_df, on='Product', how='right')
# full outer join
pd.merge(price_df, quantity_df, on='Product', how='outer')

![]() |
![]() |
![]() |
![]() |





































































