1교시

데이터 전처리

 

파이썬만으로 시각화는 불가능 시각화 툴인 판다스를 활용해야한다.  

데이터 처리, 가공에서는 판다스를 가장 많이 쓴다.

판다스에서 db에 저장하거나 가공해서 sql에서 사용 

#파일 불러오기 
import pandas as pd

kbo = pd.read_csv("./kbo_국내.csv")

kbo.shape

 

EDA(Exploratory Data Analysis / 탐색적 데이터 분석)

* 전처리 전 단계 (먼저 데이터를 파악하는 단계이다, 데이터가 싱싱한지 결측치 이상치 등을 파악)

 

이상치 / 결측치 파악

kbo.isnull().sum()

>> 특정 컬럼에 결측치가 많다면 바로 확인 필요

 

# 데이터 종류

양적데이터 : 숫자 (회사 지출비용, 순이익, 연봉 등)

질적데이터(범주형데이터) : 등급, 포지션 등 

       ㄴ 범주형 데이터 분류 : 1.순서가 없는 데이터(혈액형 등) 2.순서가 있는 데이터(등급, 고과 등)

 

데이터 타입에 따라서 적용할 수 있는 함수가 다르다. 

 

kbo.describe()

 

kbo['연봉']

>> 연봉이지만 데이터 타입이 텍스트(object) 로 되어 있다. >> 데이터 타입을 바꿔야함.

 

#'만원'을 우선 없애기
kbo['연봉'].apply(lambda x : x.replace("만원",""))

>> 다만 아직도 object 이다 >> int 로 변경할 필요가 있음

 

#int로 만들고 그걸 ['연봉']에 덮어서 변환 하겠다. 
kbo['연봉'] = kbo['연봉'].apply(lambda x : int(x.replace("만원","")))

 

kbo['연봉'].describe()

count = 연봉 갯수

mean = 평균

std = 표준편차

min = 최솟값

50% = 중앙값 (데이터 정렬 후 딱 중앙에 있는 사람을 뽑았을때) 

max = 최대값

 

* 박스 플롯 그리기 (설치 필요)

#프로그램 설치
import matplotlib.pyplot as plt

다만, 이뻐서 잘 안쓴다.

#맷플롯에서 추가 기능이 있는 프로그램
#초반에 맷플롯이 깔려 있지 않다면 오류
pip install seaborn

import seaborn as sns
sns.boxplot(data=kbo, x = '연봉')

 

#한글 폰트가 안 보인다면, 맥은 다른 방법으로 다운 필요
import matplotlib.pyplot as plt
plt.rcParams['font.family'] = 'Malgun Gothic'
#sns.set_style("ggplot")
sns.boxplot(data=kbo, x = '연봉', y='team')
plt.show()

 

 

이상치(outlier)

 

a = kbo[kbo['team']=='상무']['연봉']
b = a.values
b_mean = b.mean()
b_mean
import numpy as np
np.sqrt(np.mean((b - b_mean) **2))

 

#자유도 0 / 1 은 다르다.
a.std(ddof=0)

 

help(a.std)

> 결과 

 

 

 

 

 

*띄어쓰기 없애기 

 

#띄어쓰기 없어짐
'상무 '.strip()
kbo['team'] = kbo['team'].apply(lambda x : x.strip())

 

 

* 팀이 상무인 선수만 추출

kbo[kbo['team']=='상무']

 

 

 

#연봉을 팀별로 보고 싶다. 
#시리즈 형태 
kbo.groupby(['team'])[['연봉']].mean()

 

 

* 데이터 솔팅

#데이터 프레임 형태, #특정 함수를 솔팅하고 싶다면 sort_values
kbo.groupby(['team'])[['연봉']].mean().sort_values(by=['연봉'], ascending=False)

 

 

#평균 말고 다른 것도 보고싶다. 여러개 보고 집계를 하고 싶어.
kbo.groupby(['team'])[['연봉']].agg(['mean','count','std','median'])

 

 

#포지션도 같이 보고싶어
kbo.groupby(['team','포지션'])[['연봉']].agg(['mean','count','std','median'])

 

 

 

#팀, 포지션 별로 연봉
kbo_agg = kbo.groupby(['team','포지션'])[['연봉']].mean().sort_values(by=['연봉'],ascending=False )

 

 

 

kbo_agg.index

 

 

 

#인덱스를 컬럼으로 하고 싶다면(인덱스에 있는 데이터가 컬럼으로 넘어왔따)
kbo_agg.reset_index()

 

 

#끝났다 싶으면 inplace
kbo_agg.reset_index(inplace=True)
#팀은 내림차순, 포지션은 오름차순
kbo_agg.sort_values(by=['team','포지션'], ascending = [False, True])

 

#문자열로 집어넣어, 숫자에 콤마를 찍어라!
kbo_agg2['연봉2'] = kbo_agg2['연봉'].apply(lambda x : "{:,}".format(round(x)))

 

#선수를 가장 많이 배출한 초등학교 구하기 
#- 기준으로 자르고 싶다.
kbo['경력'].str.split("-",expand=True)

 

 

 

학부 = kbo['경력'].str.split("-",expand=True)
#고등학교 까지만 보고싶어
#iloc> 번호 갖고 위치를 얘기한다. ,오른쪽은 행 / ,왼쪽은 컬럼 / :표시는 전체를 의미한다. / 3 치면 2까지 보여준다.
학부.iloc[ : , :3]

 

 

학부 = 학부.iloc[ : , :3].copy()
#컬럼에 이름 붙이기
학부.columns = ['초','중','고']

 

#각 값을 카운트 해줘 = value_counts()
학부['초'].value_counts()

 

#비율을 알고 싶다면
학부['초'].value_counts(normalize=True)

 

 

 

#컬럼명 바꾸기
학부.rename(columns={'초':'초등학교','중':'중학교','고':'고등학교'})

 

 

#이상이 없는것을 확있했다면 바로  적용 필요
학부.rename(columns={'초':'초등학교','중':'중학교','고':'고등학교'}, inplace=True)

 

#이름으로 적용된다. *숫자는 인덱스
학부.loc[ : , ['초등학교','중학교',]]

 

 

#행을 구분하자면 #이름이다.
학부.loc[ 0:2 , ['초등학교','중학교',]]

 

 

학부.iloc[ 0:2 ,[0,1]]

 

#concat 으로 데이터 합침, axis 1은 가로로, axis 0 은 세로로 붙인다 
pd.concat([kbo,학부],axis=1)

 

#전제조건 raw 값이 같아야해, 인덱스 같은 정보가 있어야해 
kbo2 =  pd.concat([kbo, 학부], axis=1)
#부산수영초 뽑기
kbo2[kbo2['초등학교'] == '부산수영초'].groupby(['team'])[['초등학교']].count().sort_values(by=['초등학교'],ascending=False)
#team 은 인덱스로 들어갔어

 

#인덱스를 컬럼으로 변경하고 싶을때 #(/는 다음 줄도 같은 행에 있다는 것을 알려주는 것
kbo2[kbo2['초등학교'] =='부산수영초'].groupby(\
    ['team'], as_index=False)[['초등학교']].count().sort_values(by=['초등학교'], ascending=False)

 

#수영초가 들어간 팀
a= kbo2[kbo2['초등학교'] =='부산수영초'].groupby(\
    ['team'], as_index=False)[['초등학교']].count().sort_values(by=['초등학교'], ascending=False)['team'].tolist()

b = kbo2.team.unique().tolist()

 

 

#a와 b 차 집합을 하면 수영초가 없는 팀이 나온다. 
set(b)- set(a)

 

 

#각 팀별로 연봉 많이 받는 사람 한명 확인
kbo2.sort_values(by=['연봉'], ascending=False).groupby(['team']).first()

 

#bmi가 높은 사람 뽑아보기
#기존 변수에서 새로운 변수 만들었음 >> 파생변수
#신장 파생변수 만들기
kbo2['신장'] = kbo2['신장/체중'].apply(lambda x : int(x.split("/")[0].replace("cm","")))
#bmi
kbo2['체중'] / (kbo2['신장']/100) **2
#체중 파생변수 만들기
kbo2['체중'] = kbo2['신장/체중'].apply(lambda x : int(x.split("/")[1].replace("kg","")))

 

kbo2['bmi'] = kbo2['체중'] / (kbo2['신장']/100) **2
#팀별로 bmi 가장 높은 사람 뽑아보기
kbo2.sort_values(by=['bmi'], ascending=False).groupby(['team']).first()

 

 

 

#axis = 1 은 컬럼이라는 뜻 #inplace를 해야 적용
kbo2.drop(['신장/체중','경력'], axis =1, inplace=True)

 

#컬럼 위치를 바꾸고 싶어 
kbo2.columns

> 칼럼을 먼저 뽑고 복사

 

kbo2 = kbo2[['team','선수명', '등번호', '생년월일', '포지션', '입단 계약금', '연봉', '지명순위', '입단년도',
     '초등학교', '중학교','고등학교', '신장', '체중', 'bmi']].copy()

 

kbo2[kbo2['team'] == 'KIA 타이거즈']

 

 

*바차트

kbo2[kbo2['team'] == 'KIA 타이거즈']['bmi'].plot(kind='bar')

 

 

sns.barplot(x = kbo2[kbo2['team'] == 'KIA 타이거즈']['선수명'], y =   kbo2[kbo2['team'] == 'KIA 타이거즈']['bmi'])

 

#그림을 키우고 싶다면? 
plt.figure(figsize=(20,5))
sns.barplot(x = kbo2[kbo2['team'] == 'KIA 타이거즈']['선수명'], y =   kbo2[kbo2['team'] == 'KIA 타이거즈']['bmi'])

 

#차트에다가 이름을 45도로 꺽어서 넣음
plt.figure(figsize=(20,5))
chart = sns.barplot(x = kbo2[kbo2['team'] == 'KIA 타이거즈']['선수명'], y =   kbo2[kbo2['team'] == 'KIA 타이거즈']['bmi'])
chart.set_xticklabels(chart.get_xticklabels(), rotation=45)

 

 

웹을 제어 하고 싶다면? #셀레니움 

#웹드라이버매니저 설치해야 함 
#회사에서 쓰게되면 파이썬 버전이 여러개 나눠짐. 
#크롬을 제어할 있는 것 셀레니움
#이것을 악용하게 되면 매크로, 봇 이 된다.
#셀레니움 자동화 테스트 하다가 용도가 변경 된 것

pip install selenium
pip install webdriver_manager

#virtualenv >> 파이썬 친해지고 그러면 프라이버시 모드로 활용 가능

 

#크롬 버전 바꿔야함
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.chrome.service import Service
driver = webdriver.Chrome(service=Service(ChromeDriverManager(driver_version="131.0.6778.109").install()))
# 그럼 data; 창이 뜬다 >> 창이 팝업 된 뒤에 뒤에 것들이 실행 된다. 
#get 은 내가 chrome을 통해서 네이버 카페로 이동 하겠다. 
driver.get("http://cafe.naver.com")

 

driver.get("https://www.koreabaseball.com/Record/Player/HitterBasic/BasicOld.aspx")
from selenium.webdriver.common.by import By
driver.find_element(By.CSS_SELECTOR, "#contents > div.sub-content > div.tab-depth2 > ul > li:nth-child(2) > a").click()

>> 위의 # contents  찾는 법은 아래 참고

 

driver.get("https://www.koreabaseball.com/Record/Player/HitterBasic/BasicOld.aspx")

 

 

 

 

 

 

 

 

from bs4 import BeautifulSoup
import io
pd.read_html(io.StringIO(driver.page_source))[0]
driver.find_element(By.CSS_SELECTOR,
            "#cphContents_cphContents_cphContents_ucPager_btnNo2").click()
pg1 = pd.read_html(io.StringIO(driver.page_source))[0]
driver.find_element(By.CSS_SELECTOR,
            "#cphContents_cphContents_cphContents_ucPager_btnNo2").click()
#데이터 로딩이 된 후 가져와야 한다. 
import time
time.sleep(2)
pg2 = pd.read_html(io.StringIO(driver.page_source))[0]
타자 = pd.concat([pg1],[pg2] )
타자 = pd.concat([pg1,pg2], ignore_index=True)
타자.columns
#corr 만 쓰면 상관 관계가 나온다. 
타자[[ 'AVG', 'G', 'PA', 'AB', 'R', 'H', '2B', '3B', 'HR',
       'TB', 'RBI', 'SAC', 'SF']].corr()
#시각화 -> 히트맵
#상관관계를 볼때는 데이터 자체가 int 여야 한다. 
sns.heatmap(타자[[ 'AVG', 'G', 'PA', 'AB', 'R', 'H', '2B', '3B', 'HR',
       'TB', 'RBI', 'SAC', 'SF']].corr())

 

 

#타자 기준으로 kbo 데이터를 합치고 싶다. 
#팀, 이름으로 조인을 해야하지만 중복되어서 데이터가 이상해 질수 있어
#팀을 처리를 해줘야해
kbo2['팀명'] = kbo2['team'].apply(lambda x : x.split()[0])
kbo2['팀명'].unique()
타자['팀명'].unique()

 

#merge 를 한다
#합칠떄 기준을 먼저 왼쪽에 적는다.
#how 에는 inner, right, outer 도 쓸 수 있음
타자2 = pd.merge(타자, kbo2, left_on=['팀명', '선수명'], right_on=['팀명','선수명'], how='inner')

 

타자2[['AVG','연봉']].corr()

 

 

#히스토그램

kbo2['포지션'].hist()

+ Recent posts