<jupyter_start><jupyter_text>[View in Colaboratory](https://colab.research.google.com/github/Dalbongjooin/tutorial/blob/master/20180726_library.ipynb) 공공데이터포털의 [전국도서관표준데이터](https://www.data.go.kr/dataset/15013109/standard.do) 일부를 실습용으로 가공하였습니다. 사전 준비<jupyter_code># 나눔글꼴 설치
!apt install fonts-nanum

# Plotnine 패키지 설치
!pip install plotnine

# 기본 글꼴 변경
import matplotlib as mpl
mpl.font_manager._rebuild()
mpl.pyplot.rc('font', family='NanumBarunGothic')

# 레티나 디스플레이 지원
%config InlineBackend.figure_format = 'retina'<jupyter_output>Reading package lists... Done
Building dependency tree       
Reading state information... Done
fonts-nanum is already the newest version (20161025-1).
0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
Requirement already satisfied: plotnine in /usr/local/lib/python3.6/dist-packages (0.3.0)
Requirement already satisfied: numpy in /usr/local/lib/python3.6/dist-packages (from plotnine) (1.14.5)
Requirement already satisfied: pandas>=0.21.0 in /usr/local/lib/python3.6/dist-packages (from plotnine) (0.22.0)
Requirement already satisfied: six in /usr/local/lib/python3.6/dist-packages (from plotnine) (1.11.0)
Requirement already satisfied: scipy>=1.0.0 in /usr/local/lib/python3.6/dist-packages (from plotnine) (1.1.0)
Requirement already satisfied: matplotlib>=2.1.0 in /usr/local/lib/python3.6/dist-packages (from plotnine) (2.1.2)
Requirement already satisfied: patsy>=0.4.1 in /usr/local/lib/python3.6/dist-packages (from plotnine) (0.5.0)
Requirement already satisfied: mizani>=0.[...]<jupyter_text>데이터 읽어오기.<jupyter_code>import pandas as pd
import numpy as np
from plotnine import *

src = pd.read_csv('https://s3.ap-northeast-2.amazonaws.com/data10902/messy/library.csv')<jupyter_output><empty_output><jupyter_text>데이터 복사본 만들기. 중간에 데이터가 망가지면 이 셀부터 다시 실행하면 됩니다 :)<jupyter_code>df = src.copy()
df.head(3)<jupyter_output><empty_output><jupyter_text>데이터 살펴보기시도별 도서관 수는?<jupyter_code>result = df['도서관명'].str.extract(r'\(([^)]+)\)$', expand = False).value_counts()
# \(([^)]+)\)$
# [^abc : Not a or b or c
# expand = True : DataFrame형식을 return 합니다.
# expand = False: 객체나 정규표현식 패턴에 따라 \
# Series, Index,  또는 DataFrame형식을 return합니다. 
# pandas version 0.23.0부터는 expand=True가 기본값입니다.

# 정규표현식에서 extract는 먹는다는 방식으로 이해하면 될 듯 ! 
result

# 그래프로 확인해봅니다. 
result.plot.barh(color='steelblue')<jupyter_output><empty_output><jupyter_text>소장자료수(도서, 연속간행물, 비도서를 모두 합한 값)가 가장 많은 도서관은?<jupyter_code>#[]은 가장 기본적인 인덱싱방법입니다.
# DataFrame에서 frame[column_name]을 하면 칼럼 전체의 데이터가 선택되며,
# 이는 series type으로 변환되어 return됩니다. 

# 이 시리즈 타입의 데이터를 더하면 int64 type를 return합니다. 


df['자료수'] = df['도서'] + df['연속간행물'] + df['비도서']

df['자료수']


#df를 찍어보면 칼럼이 하나 추가되었습니다. 
df.head()



#자료수가 가장 많은 순서대로 정렬해봅니다. 
# 함수는 sort_values()를 사용합니다. 
#sort_values(by, axis=0, ascending=True, inplace=False, kind='quicksort', na_position='last')
df.sort_values(by='자료수', ascending = False)<jupyter_output><empty_output><jupyter_text>일요일에 쉬는 도서관은?<jupyter_code># "삽질할 수 있는 환경 만들기.""
# 휴관일의 unique값을 뽑아내서 
# 어떤 것을 정규표현식을 이용해 extract하면 좋을지본다.
# 이를 regex101.com으로 옮겨서 연습을 해보면 좋다! 
df['휴관일'].unique()
df['휴관일'].str.extractall(r'(일요일|[\b\s,]일[\b\s,]|주말)')


#차집합으로 확인하기.

pattern = r'일요일|[\b\s,]일[,\s\b]|주말'


a = set(df['휴관일'])

# datatype set ex)  a = set('abracadabra')
#                   a
#                   {'a', 'r','b', 'd 'c'}
#순서가 없음, unique한 letter를 뽑아줌. 

b = set(df['휴관일'][df['휴관일'].str.contains(pattern)])

# df['휴관일']중에서 pattern 과 일치하는 것을 indexing한다. 
# 이 series들을 set type으로 만듦. 


print(a - b) 

# 여기서 일요일이 안찍히면 성공! 


# 마지막으로 일요일에 쉬는 도서관 loc()함수로 확인! 

df.loc[df['휴관일'].str.contains(pattern)][['도서관명', '휴관일']]<jupyter_output><empty_output><jupyter_text>데이터 다듬기"위도"와 "경도" 분리하기.<jupyter_code>df.head()
# 글자수가 같다는 점에서 착안해 slice()함수 이용하기.

temp = df.loc[df['위경도'].str.len() == 20]['위경도']


temp.str.slice(0, 9)
#1.본 데이터의 '위경도' col 에서 ','을 기준으로 좌는 위도, 우는 경도 입니다
#2.좌 , 우 를 나눠서 '위도','경도' 라는 col 을 새로 생성해서 넣어주는 과정입니다.

df['위도'] = df['위경도'].str.extract(r'(\w+),\w+', expand=False).astype(np.float32)
df['위도']

df['경도'] = df['위경도'].str.extract(r'.+,(.+)', expand=False).astype(np.float32)
# 1.expand = False 라면 'series' 타입으로 평가합니다. 
#2.astype 은 데이터 타입을 바꿔주는 함수 입니다 .
result = pd.DataFrame(df['위경도'].str.split(',',1).tolist(),columns = ['위도','경도'])
result<jupyter_output><empty_output><jupyter_text>(잠깐 재미로) 지도 그려보기.<jupyter_code>(
    ggplot(aes(x='경도', y='위도'), df) +
    geom_point() +
    xlim([124, 131]) +
    ylim([33, 38.5])
)<jupyter_output>/usr/local/lib/python3.6/dist-packages/plotnine/layer.py:450: UserWarning: geom_point : Removed 1171 rows containing missing values.
  self.data = self.geom.handle_na(self.data)<jupyter_text>"도서관명"과 "지역" 분리하기.<jupyter_code>df['시도'] = df['도서관명'].str.extract(r'\(([^)]+)\)$', expand=False)
df.head()

# df['도서관명'] = df['도서관명'].str.split('(', expand = True)[0]
# df['도서관명']
df.head()<jupyter_output><empty_output><jupyter_text>관찰 단위(observational units)에 따라 표 두 개(도서관, 소장자료)로 분리하기.<jupyter_code>libraries = df[['key', '도서관명', '시도', '위도', '경도' , '좌석수', '전화번호', '휴관일']]
collections = df[['key', '도서', '연속간행물','비도서']]<jupyter_output><empty_output><jupyter_text>칼럼 제목에 담긴 데이터(범주형 데이터)를 변수로 만들기.<jupyter_code>libraries.head()
collections.head()
collections = collections.melt(id_vars='key', value_vars=['도서','연속간행물','비도서'],
                 var_name='종류',
                 value_name = '수량')

collections.head()<jupyter_output><empty_output><jupyter_text>휴관일은 어떻게 하면 좋을까?<jupyter_code>import re
#1
def cleanse_closing(raw):
  rules = {
      r'매주': '',
      r'요일': '',
      r'주말': '토일',
      r'(법정|국가지정)?\s*공휴일': '공',    
      r'[^월금토일공]': '',
  }
#2
  for pattern, replacer in rules.items():
    raw = re.sub(pattern, replacer, raw)
  return raw

#3
pairs = [(raw, cleanse_closing(raw)) for raw in set(df['휴관일'])]
for raw, clean in pairs:
  print(raw, '=>', clean)
df['휴관일'] = df['휴관일'].apply(cleanse_closing)
df.head()<jupyter_output><empty_output><jupyter_text>하나의 칼럼에는 하나의 변수만 담겨야 하니까 "휴관일" 안에 담긴 여러 변수를 각 칼럼(월, 금, 토, 일, 공휴일)으로 나눠보자.<jupyter_code>for day in list('월금토일공'):
  df[day] = df['휴관일'].str.contains(day)
df.head()<jupyter_output><empty_output><jupyter_text>새로운 관찰단위 "closings"를 추가해 보자<jupyter_code>closings = df[['key', '월', '금', '토', '일', '공']]
closings = closings.melt(
    id_vars='key',
    value_vars=['월', '금', '토', '일', '공'],
    var_name='휴일',
    value_name='휴일여부'
)
closings.head()
#휴일 여부 col 은 사실 필요가 없기 때문에<jupyter_output><empty_output><jupyter_text>데이터 다시 살펴보기시도별 도서관 수는?<jupyter_code>libraries['시도'].value_counts()<jupyter_output><empty_output><jupyter_text>데이터 저장하기다듬어진 데이터를 파일로 저장하기<jupyter_code>with open('library.csv', 'w') as f:
 df.to_csv(f)

from google.colab import files
files.download('library.csv')<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.18179108925644463, 'fraction_numerical': 0.020265236179406943, 'mean_word_length': 4.887719298245614, 'pattern_counts': {'":': 0, '<': 63, '<?xml version=': 0, '>': 69, 'https://': 3, 'lorem ipsum': 0, 'www.': 1, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '16', 'dir': 'jupyter-structured-clean-dedup', 'id': '333625', 'license': 'MIT', 'n_tokens_mistral': 3662, 'n_tokens_neox': 4209, 'n_words': 577, 'path': 'Tutorial_20180726_library.ipynb', 'repo_name': 'jypark0407/tutorial', 'size': '6711'}