본문 바로가기
CS/DataAnalysis

정형 데이터의 전처리 / 탐색 /시각화

by zieunee 2019. 2. 19.
반응형

정형 데이터의 전처리 / 탐색 /시각화

정형 데이터 ?

엑셀형태의 수치형 데이터 , 행방향이던 열이던 연산을 할 수 있다.


반정형 데이터

텍스트 데이터 , 구조는 있으나 이걸가지고 수학적인 계산을 할 수는 없다. 결국 비정형데이터에 있는 문서이다.


비정형 데이터

어디에나 있는 데이터 글, 사진,음성 등등

==> 비정형데이터를 정형데이터로 바꿀 수 있다.

ex> 가로세로가 10px 짜리가 있다. 흑백 image 를 픽셀단위로 작게 자르면 1*1의 0~1사이의 숫자로 표현할 수 있다(w/b) / image한장은 백개의 픽셀이 늘어져 있는 형태로 바꿀 수 있다.

0~1 의 1행 * 100열


다양한 툴들이 있다.

  • Google Analytics(facebook Naver..)

  • Elastic stack (kibana, Elastic search, Logstash)

  • Zeppelin


타사의 데이터

Use API & Web srcaper

  • APIs(twitter, facebook, intagram)

  • Bots(web crawler , web scraper)

왜 API열어놓지?

  • 서비스의 가치가 올라간다.

  • 서버가 표적이 많이 된다. (허락한 데이터만 가져가!)

  • 이런 API는 성능떨어지는 것이다.


opendata

  • 공공데이터 포털

  • 국가 통계포털

  • MDIS


etc

  • Awesome Public Datasets(깃헙)

  • Google Dataset Search

  • Kaggle competition datasets 등



read_clipboard

웹상에서 테이블 가져올 수 있다.

read_excel

엑셀파일 가져올 수 있다.

Pandas tutorial (for practice)

import numpy as np
import pandas as pd
import seaborn as sns

df = pd.read_excel('animals.xlsx', encoding='utf-8') # Shift+Tap!
df #DataFrame, Series

df.head() # 머리!
df.tail() # 꼬리!
df.describe() #전반적인 분포
df.info()#몇개의 비어있지 않은 데이터가 있는지

df['name'].head() # 하나의 열 출력하기
df[['name', 'hair', 'feathers']].head() # 여러개의 열 출력하기

sample_dict= {'Dog':'멍멍' ,'Cat' :'야옹'}
sample_dict['Dog'] ##'멍멍'


df_new = df['name', 'hair', 'feathers', 'eggs', 'milk', 'type'] # 에러
#--->리스트로 꺼내야 한다.
df_new = df[ ['name', 'hair', 'feathers', 'eggs', 'milk', 'type'] ]
df_new.head()

# hair 열에 1을 더한 새로운 열을 new_hair 로 추가하기 ______1)
df_new['new_hair'] = df_new['hair'].apply(lambda x : x+1) # '적용하다' 를 영어로?
df_new.head()

# Type 을 index 로 하는 새로운 df 만들기 (엑셀의 pivot table 과 유사) ___2)
pivot_df = pd.pivot_table(df_new, index='type', aggfunc=np.sum) # Shift+Tab! 원본데이터 타입 로드받음 / type이 기준이다.
pivot_df = pd.pivot_table(df_new, index='type', aggfunc=np.max) #mean도 가능
#type 마다 여러개의 행들이 묶여있다. 어떤 것을 가져올거냐 numpy에 있는 sum함수를 가져온다 max함수를 가져온다 라는의미

# 열 삭제하기
#new_hair가 필요하지 않다면?
del pivot_df['new_hair']
pivot_df

# 행 삭제하기
pivot_df = pivot_df.drop([3]) # Database 에서 data point 를 drop! 3이라는 행을 찾아서 지운다.
#리스트로 여러개의 행을 줄 수 있다

# 열 이름 바꾸기
# '이름을 바꿔주다'?
new_pivot = pivot_df.rename(columns = {'eggs':'산란', 'feathers':'깃털'})
new_pivot.head()
##이것을 ---->
pivot_df.rename(columns = {'eggs':'산란', 'feathers':'깃털'}, inplace=True)
pivot_df.head()      # inplace 옵션 == 덮어쓰기 여부이다. 안하면 줄이 안바뀐다.
# 이렇게 바꿔준다.

#열이름을 통째로 바꿔주려면 ?
pivot_df.columns = [~,~,~,~] #이런식으로 쓰면 된다.

# 산란 수 기준으로 정렬하기
pivot_df.sort_values(by='산란', inplace=True) # 내용(value)을 기준으로 정렬(sort), inplace=True : 덮어쓰기
pivot_df.head()

# 산란 수 기준으로 내림차순 정렬하기
pivot_df.sort_values(by='산란',ascending =False, inplace=True)
pivot_df.head()

# 얕은 복사와 깊은 복사
pivot_df_2 = pivot_df # shallow copy
pivot_df_3 = pivot_df.copy() # deep=True, deep copy

del pivot_df['산란']

pivot_df_2.head(3) # 원본 DataFrame인 pivot_df와 연결되어 있습니다.

pivot_df_3.head(3) # 원본 DataFrame인 pivot_df로부터 분리되어 별도로 존재합니다.

1) 번 추가 설명

namehairfeatherseggsmilktype
0aardvark10011
1antelope10011
2bass00104
3bear10011
4boar10011

--> new_hair 추가

namehairfeatherseggsmilktypenew_hair
0aardvark100112
1antelope100112
2bass001041
3bear100112
4boar100112

2)번추가설명

eggsfeathershairmilknew_hair
type
110394180
220200020
340005
41300013
540004
6804012
7900010


  1. 데이터 입력및 데이터 전처리

  1. 데이터 탐색

  1. 데이터 시각화


3. 서울시 범죄현황 통계자료 분석 및 시각화 (for practice)

import numpy as np
import pandas as pd
import seaborn as sns

import matplotlib.pyplot as plt
from matplotlib import font_manager, rc # rc == run configure(configuration file)


데이터 입력 및 데이터 전처리

# 서울시 관서별 5대 범죄 발생 & 검거 현황 @ data.go.kr
# 원본 데이터 및 전처리 작업을 위한 파이썬 코드 @ folder named [ Original data source & data preprocessing (5대범죄 & 인구수) ]

df = pd.read_excel('관서별 5대범죄 발생 및 검거.xlsx', encoding='utf-8') # 엑셀 파일 읽기?

df.head() # 데이터의 윗 부분만 살펴보려면?

--> 구별 데이터를 만들고 싶다


경찰서를 구별로 정리하기

# 서울시 경찰청의 소속 구 @ https://goo.gl/MQSqXX
police_to_gu = {'서대문서': '서대문구', '수서서': '강남구', '강서서': '강서구', '서초서': '서초구',
               '서부서': '은평구', '중부서': '중구', '종로서': '종로구', '남대문서': '중구',
               '혜화서': '종로구', '용산서': '용산구', '성북서': '성북구', '동대문서': '동대문구',
               '마포서': '마포구', '영등포서': '영등포구', '성동서': '성동구', '동작서': '동작구',
               '광진서': '광진구', '강북서': '강북구', '금천서': '금천구', '중랑서': '중랑구',
               '강남서': '강남구', '관악서': '관악구', '강동서': '강동구', '종암서': '성북구',
               '구로서': '구로구', '양천서': '양천구', '송파서': '송파구', '노원서': '노원구',
               '방배서': '서초구', '은평서': '은평구', '도봉서': '도봉구'}

# dict[칼럼명].apply(칼럼 내 데이터마다 적용할 함수)
# dict.get(key)는 value 를 return
df['구별'] = df['관서명'].apply(lambda x: police_to_gu.get(x, '구 없음')) # 적용하다?
df.head()

# 관서별 데이터를 구별 데이터로 변경 (index : 관서 이름 -> 구 이름, column은 자동으로 오름차순 정렬됨)
# 같은 구의 경우에는 sum 을 적용
gu_df = pd.pivot_table(df, index='구별', aggfunc=np.sum) # 피봇 테이블을 만드려면? / sum은 무슨역할? : 중부에는 남대무서도 있다 하나의 구에 2개이상 경찰서가 있다. 그런 상태에서 너가 원하는 계산이 뭐냐? 강도,살인등 건수를 경찰서별로 범죄를 합산해줘라!
gu_df

gu_df = gu_df.drop(['구 없음']) # 행을 삭제할 때? (Database)
gu_df


범죄별로 검거율 계산하기

# 발생건수 대비 검거건수 -> 검거율 데이터 column을 범죄별로 생성
gu_df['강간검거율'] = gu_df['강간(검거)']/gu_df['강간(발생)']*100
gu_df['강도검거율'] = gu_df['강도(검거)']/gu_df['강도(발생)']*100
gu_df['살인검거율'] = gu_df['살인(검거)']/gu_df['살인(발생)']*100
gu_df['절도검거율'] = gu_df['절도(검거)']/gu_df['절도(발생)']*100
gu_df['폭력검거율'] = gu_df['폭력(검거)']/gu_df['폭력(발생)']*100
gu_df['검거율'] = gu_df['소계(검거)']/gu_df['소계(발생)']*100

# 필요없는 column 지우기 (범죄별 발생 건수와 검거율만 남긴다)
# df.drop(['row']) : 해당 행 데이터를 drop
# del df['column'] : 해당 열 데이터를 drop
# 여러 줄을 한번에 수정할 때
del gu_df['강간(검거)']
del gu_df['강도(검거)']
del gu_df['살인(검거)']
del gu_df['절도(검거)']
del gu_df['폭력(검거)']
del gu_df['소계(발생)']
del gu_df['소계(검거)']  #한꺼번에 한다면? ctrl누르고 마우스로 하나하나 선택한 후에 수정

# 발생건수는 2016이고, 그 전에 발생한 범죄에 대한 검거가 2016에 이뤄지면 검거수에 반영된 것
# if 문을 쓸 필요 없이 바로 boolean 체크 후 값 대입 적용이 가능
gu_df[ gu_df[['강간검거율', '강도검거율', '살인검거율', '절도검거율', '폭력검거율']] > 100] = 100
gu_df.head(10)
# gu_df[['강간검거율', '강도검거율', '살인검거율', '절도검거율', '폭력검거율']] 는 특정한 데이터만 꺼내는 것 이게 100보다 크면? 100으로 바꿔줘라!

# 새롭게 이름을 지어줄 때?
gu_df.rename(columns = {'강간(발생)':'강간',
                       '강도(발생)':'강도',
                       '살인(발생)':'살인',
                       '절도(발생)':'절도',
                       '폭력(발생)':'폭력'}, inplace=True) # inplace 옵션 == 덮어쓰기 여부




인구 데이터 merge 하기

popul_df = pd.read_csv('pop_kor.csv', encoding='UTF-8') # CSV 는 어떻게 읽을까요? (엑셀과 유사)
# merge하려면 인덱스 열이 같아야 한다.

# 구별 index 를 기준으로 merge를 할 것이므로, index 를 세팅해주기
popul_df = pd.read_csv('pop_kor.csv', encoding='UTF-8', index_col='구별')

# 아래와 같이 먼저 read_csv()하고 .set_index()를 적용할 수도 있습니다.
# popul_df = pd.read_csv('pop_kor.csv', encoding='UTF-8').set_index('구별')


# 데이터프레임의 M&A
gu_df = gu_df.join(popul_df) # df1.join(df2) : df1 의 index를 기준으로 df2 의 index 중 매칭되는 값을 매김

# df.join() 대신 pd.merge()를 사용하여 Merge할 수 있다.
# gu_df = pd.merge(gu_df, popul_df, left_index=True, right_index=True)
# gu_df.head()

https://goo.gl/ErLHCY 데이터 시각화&차트


데이터 살펴보기 (Data exploration)

# 검거율 기준으로 오름차순 정렬하기
# '값'을 기준으로 정렬할 때?
gu_df.sort_values(by='검거율', ascending=False, inplace=True) # ascending=False : 내림차순, inplace=True : 덮어쓰기
gu_df.head()

import seaborn as sns
sns.heatmap(gu_df[['강간', '강도','살인','절도', '폭력']])
#시각화 하기







시각화하면 깨진다 -> 해결

  1. Min-max algorithm을 쓴다(=정규화) : 열의 최소값이 0 열의 최대값이 1이 되게 맞춰준다. (newX = oldX -min(열) / max(열) - min(열)) ---> 직관적임

  1. Standardization 을 쓴다 : 열마다의 평균값을 0으로 맞춰주고 표준편차의 값을 1로 맞춰준다. (newX = oldX -mean(열) / std(열)) ----> 성능이 좋음


범죄별 발생 건수 정규화하기 (범죄별로 가장 많이 발생한 구가 1 == 100%)

# 5대 범죄별 수치를 해당 범죄별 최대값으로 나눠줌 
target_col = ['강간', '강도', '살인', '절도', '폭력']
weight_col = gu_df[target_col].max()
weight_col

# target_col은 5개의 열 이것을 weight_col로 나누기 한다.
crime_count_norm = gu_df[target_col]/weight_col
crime_count_norm


한글 데이터 시각화를 위한 준비

# jupyter notebook 내에 figure를 보여주기
%matplotlib inline
# matplotlib의 한글문제를 해결
font_name = font_manager.FontProperties(fname="c:/Windows/Fonts/malgun.ttf").get_name()
# font_name
rc('font', family=font_name)
## Mac OS
# rc('font', family="AppleGothic")


구별 살인 발생 순위 살펴보기

sns.heatmap(crime_count_norm.sort_values(by='살인', ascending=False)) # 내림차순으로 정렬하려면?
import matplotlib.pyplot as plt
plt.figure

# 몇 가지 옵션으로 더 내용을 확인하기 편하도록 수정하기

# 전체 figure 의 사이즈를 조정
plt.figure(figsize = (10,10))
# annot : 셀 내에 수치 입력 여부
# fmt : 셀 내 입력될 수치의 format (f == float)
# linewidths : 셀 간 이격거리 (하얀 부분, 내부 테두리)
# cmap : matplotlib colormap @ https://goo.gl/YWpBES
sns.heatmap(crime_count_norm.sort_values(by='살인', ascending=False), annot=True, fmt='f', linewidths=.5, cmap='Reds')
plt.title('범죄 발생(살인발생으로 정렬) - 각 항목별 최대값으로 나눠 정규화')
plt.show()

# 살인 대신 절도 기준으로 살펴보기
plt.figure(figsize = (10,10))
sns.heatmap(crime_count_norm.sort_values(by=?, ascending=False), annot=True, fmt='f', linewidths=.5, cmap='RdPu')
plt.title('범죄 발생(절도발생으로 정렬) - 각 항목별 최대값으로 나눠 정규화')
plt.show()




(단순히 범죄건수만 보지 말고) 인구수로 나눠서 인구대비 발생비율로 살펴보기

crime_count_norm.head(3)
gu_df.head(3)

# 행(구)별로 구별 범죄 수 (max 대비 비율값) / 구별 인구 수 * 100000
# 인구 수 단위인 10만을 곱해준다 (강서구 강간 = 9.795665e-07 -> 0.x 까지 끌어올리기)
crime_ratio = crime_count_norm.div(gu_df['인구수'], axis='index') * 100000
crime_ratio.head()


[ 인구수 대비 ] 구별 살인 발생 순위 살펴보기

plt.figure(figsize = (10,10))

sns.heatmap(crime_ratio.sort_values(by='살인', ascending=False), annot=True, fmt='f', linewidths=.5, cmap='Reds')
plt.title('범죄 발생(살인발생으로 정렬) - 각 항목을 정규화한 후 인구로 나눔')
plt.show()


[ 인구 수 대비 ] 구별 5대범죄 발생 수치 평균

# 구별 인구 대비 
crime_ratio['전체발생비율'] = crime_ratio.mean(axis=1) # 평균?
crime_ratio.head()


[ 인구 수 대비 ] [ 5대범죄 발생 수치 평균 ] 기준 구별 순위 비교

plt.figure(figsize = (10,10))

sns.heatmap(crime_ratio.sort_values(by='전체발생비율', ascending=False), annot=True, fmt='f', linewidths=.5, cmap='Reds')
plt.title('범죄 발생(전체발생비율로 정렬) - 각 항목을 정규화한 후 인구로 나눔')
plt.show()




반응형

'CS > DataAnalysis' 카테고리의 다른 글

데이터 분석  (0) 2021.04.11
데이터 분석_설치환경구축, 라이브러리  (0) 2021.03.28
Bigdata analytics  (0) 2019.02.19