Tag Archives: Bigdata

[Python] Get volatility of Google Stock; 주식 변동성 확인

import numpy as np
import pandas as pd
import pandas.io.data as web
# Google 주가를 가져온다. 짱쉽다.
goog = web.DataReader('GOOG', data_source='google', start='1/1/2009', end='29/12/2015')

# 데이터 확인
goog.tail()
Open High Low Close Volume
Date
2015-12-22 751.65 754.85 745.53 750.00 1365520
2015-12-23 753.47 754.21 744.00 750.31 1566726
2015-12-24 749.55 751.35 746.62 748.40 527223
2015-12-28 752.92 762.99 749.52 762.51 1515716
2015-12-29 766.69 779.98 766.43 776.60 1765012
# 로그값 구함.
goog['Log_Ret'] = np.log(goog['Close'] / goog['Close'].shift(1))
# 이동표준편차
goog['Volatility']= pd.rolling_std(goog['Log_Ret'], window=252) * np.sqrt(252)
goog[['Close', 'Volatility']].plot(subplots=True, color='blue', figsize=(8, 6))

Google_stock_volatility

서울시 지하철(1~4호선) 탑승인원 데이터 분석

특별히 목적있게 정리하는게 아니라, 그냥 이것저것 해보는 용으로 정리합니다.

데이터 출처는 서울 열린데이터에서 가져온 ‘일별 지하철 탑승인원’ 이다. 링크는 귀찮다.

# -*- coding: utf-8 -*-
%matplotlib inline
import numpy as np
import pandas as pd

import matplotlib.pyplot as plt
import matplotlib

데이터를 구경해보도록 하자

# 일단 원본데이터를 구경하자.
pd.read_csv('Subway.csv')[:5]
“CHK_DATE” MONTH DAY_WK LINE_NM STN_NM SH_GBN FROM00TO01 FROM01TO02
0 2013-01-01 00:00:00.0 1 1호선 동대문(155) 승차 3 0
# 네번째 컬럼을 인덱스로 잡는다.
stn_db = pd.read_csv('Subway.csv', index_col=4, parse_dates=True)
# 역 이름이 서로 다르다. 중복되는게 있는 지 확인하자.
stn_db.index.duplicated()

중복체크결과
array([False, True, False, …, True, True, True], dtype=bool)

# index로 죄다 합치자.(평균으로)
stn_db = stn_db.groupby(stn_db.index).mean()
# 중복이 없구몬.
stn_db.index.duplicated()

array([False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False], dtype=bool)

# 인덱스확인
stn_db.index

Index([‘가락시장 (340)’, ‘가락시장(340)’, ‘강남 (222)’, ‘강남(222)’, ‘강변 (214)’, ‘강변(214)’,
‘건대입구 (212)’, ‘건대입구(212)’, ‘경복궁 (317)’, ‘경복궁(317)’,

‘합정 (238)’, ‘합정(238)’, ‘혜화 (420)’, ‘혜화(420)’, ‘홍대입구 (239)’, ‘홍대입구(239)’,
‘홍제 (314)’, ‘홍제(314)’, ‘회현 (425)’, ‘회현(425)’],
dtype=’object’, name=’STN_NM’, length=239)

 

 

stn_db.columns = (['00~01','01~02','02~03','03~04','04~05','05~06','06~07','07~08','08~09','09~10','10~11','11~12','12~13','13~14','14~15','15~16','16~17','17~18','18~19','19~20','20~21','21~22','22~23','23~24'])
# 근데 띄어쓰기 때문에 중복이 있다....
stn_db.index = [x.replace(' ', '') for x in stn_db.index]
# 없앤 김에 뒤에 숫자도 없애버리자.
stn_db.index = [x[:x.find('(')] for x in stn_db.index] 
stn_db = stn_db.groupby(stn_db.index).mean()

#Month와 tot 컬럼도 없애자.
stn_db = stn_db.drop('MONTH', 1)
stn_db = stn_db.drop('TOT', 1)

# 사실 지하철이 운행하지 않는 시간의 데이터는 의미가 없지만.. 어느정도 보기 좋게 나왔다
# 지금 문제가 몇가지 있다.
# 1. 한글이 제대로 안나온다. 폰트문제인가? matploblib의 UTF-8 문제인가?
# 2. 이렇게 plot을 여러개 선언하는거 말고 방법이 있을 것 같은데?

stn_db.ix['잠실'].plot(label='Jamsil', legend=True)
stn_db.ix['사당'].plot(label='Sadang', legend=True)
stn_db.ix['대림'].plot(label='Daerim', legend=True)
stn_db.ix['강남'].plot(label='Gangnam', legend=True)
stn_db.ix['신도림'].plot(label='Sindorim', legend=True, figsize=(12, 10))

plt.xticks(np.arange(24), np.arange(24), rotation=17)

subway

 

# 새벽 1~2시 사이에 승하차인원이 가장 많은역은?
stn_db.sort_values('01~02', ascending=False).index[:1]

Index([‘서울대입구’], dtype=’object’)
평균 90명이 오고간다..

subway2

새삼.. 공부를 더 열심히해야겠다는 생각이 든다.

[Python] 미국농무부식품 데이터베이스 분석

AWS가 t2.micro인줄 알았는데 여태 t3.meduim을 쓰고 있어서 과금이 되고 있었다.

또 Region이 왜 인지 도쿄로 되있어서 과금이 따따블로 나가고 있었다. ㅠㅠ

황급히 서버를 내리고 모두 가장 저렴한 오레곤으로 대피시켰다.

대피시키다보니 WordPress야 제대로 됐지만 ipython 을 실행시키던 ubuntu가 내려가면서 ipython 서버는 죽어버렸다.ㅠㅠ

여담이지만 무려 30mb 짜리 json 파일이다.

import numpy as np
import pandas as pd
from matplotlib import pyplot as plt

%matplotlib inline
import json

db = json.load(open('foods-2011-10-03.json'))

db[0].keys()

dict_keys([‘tags’, ‘manufacturer’, ‘portions’, ‘id’, ‘group’, ‘description’, ‘nutrients’])

db[0]['nutrients'][0]

{‘description’: ‘Protein’,
‘group’: ‘Composition’,
‘units’: ‘g’,
‘value’: 25.18}

nutrients = pd.DataFrame(db[0]['nutrients'])
description group units value
0 Protein Composition g 25.180
1 Total lipid (fat) Composition g 29.200
2 Carbohydrate, by difference Composition g 3.060
3 Ash Other g 3.280
4 Energy Energy kcal 376.000
5 Water Composition g 39.280
6 Energy Energy kJ 1573.000
7 Fiber, total dietary Composition g 0.000
8 Calcium, Ca Elements mg 673.000
info_keys = ['description', 'group', 'id', 'manufacturer']
info = pd.DataFrame(db, columns=info_keys)
description group id manufacturer
0 Cheese, caraway Dairy and Egg Products 1008
1 Cheese, cheddar Dairy and Egg Products 1009
2 Cheese, edam Dairy and Egg Products 1018
3 Cheese, feta Dairy and Egg Products 1019
4 Cheese, mozzarella, part skim milk Dairy and Egg Products 1028
5 Cheese, mozzarella, part skim milk, low moisture Dairy and Egg Products 1029
pd.value_counts(info.group)[:10]

Vegetables and Vegetable Products 812
Beef Products 618
Baked Products 496
Breakfast Cereals 403
Fast Foods 365
Legumes and Legume Products 365
Lamb, Veal, and Game Products 345
Sweets 341
Pork Products 328
Fruits and Fruit Juices 328
Name: group, dtype: int64

nutrients = []

for rec in db:
    fnuts = pd.DataFrame(rec['nutrients'])
    fnuts['id'] = rec['id']
    nutrients.append(fnuts)

nutrients = pd.concat(nutrients, ignore_index=True)
description group units value id
0 Protein Composition g 25.180 1008
1 Total lipid (fat) Composition g 29.200 1008
2 Carbohydrate, by difference Composition g 3.060 1008
3 Ash Other g 3.280 1008
4 Energy Energy kcal 376.000 1008
5 Water Composition g 39.280 1008
nutrients.duplicated().sum()
nutrients = nutrients.drop_duplicates()

col_mapping = {'description': 'food', 'group':'fgroup'}
info = info.rename(columns=col_mapping, copy=False)
col_mapping = {'description':'nutrient', 'group':'nutgroup'}
nutrients = nutrients.rename(columns=col_mapping, copy=False)

result = ndata.groupby(['nutrient', 'fgroup'])['value'].quantile(0.5)
result['Calcium, Ca'].order().plot(kind='barh')

food

[Python] 2016 미국 대통령 선거 기부자 명단 데이터베이스 분석

2016년 미국 대통령 선거 후보자들의 기부금액을 따로 저렇게 관리를 한다고 한다.
누가 얼마를 냈고, 그사람 직업은 뭔지 다 나온다. 엄청나다.
분석을 해보자.
자료 출처는 이곳이다.

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

# 인덱스컬럼이 없는 상태로 읽어온다. 안그러면 맨 첫번째 컬럼을 인덱스로 읽어온다.
fec = pd.read_csv('donation.csv', index_col=False)

# 내가 하나하나 다 맵핑했다. 민주당 후보는 왜케 없음????
parties = {'Rubio, Marco': 'Republican'
         , 'Santorum, Richard J.': 'Republican'
         , 'Perry, James R. (Rick)': 'Republican'
         , 'Carson, Benjamin S.': 'Republican'
         , "Cruz, Rafael Edward 'Ted'": 'Republican'
         , 'Paul, Rand': 'Republican'
           , 'Clinton, Hillary Rodham': 'Democratic'
           , 'Sanders, Bernard': 'Democratic'
           , 'Fiorina, Carly': 'Republican'
           , 'Huckabee, Mike': 'Republican'
           , 'Pataki, George E.': 'Republican'
           , "O'Malley, Martin Joseph": 'Democratic'
           , 'Graham, Lindsey O.': 'Republican'
           , 'Bush, Jeb': 'Republican'
           , 'Trump, Donald J.': 'Republican'
           , 'Jindal, Bobby': 'Republican'
           , 'Christie, Christopher J.': 'Republican'
           , 'Walker, Scott': 'Republican'
           , 'Webb, James Henry Jr.': 'Democratic'
           , 'Kasich, John R.': 'Republican'
           , 'Lessig, Lawrence': 'Democratic'
          }

# 데이터 한줄은 이렇게 구성된다.
fec.ix[123456]

데이터 한줄을 뽑아와보자

cmte_id C00574624
cand_id P60006111
cand_nm Cruz, Rafael Edward ‘Ted’
contbr_nm SMITH, CARL
contbr_city MORTON
contbr_st MS
contbr_zip 3.91179e+08
contbr_employer IRBY CONST. CO.
contbr_occupation TRUCK DRIVER
contb_receipt_amt 35
contb_receipt_dt 09-AUG-15
receipt_desc NaN
memo_cd NaN
memo_text NaN
form_tp SA17A
file_num 1029462
tran_id SA17.440359
election_tp P2016
Name: 123456, dtype: object

# 이제 후보자들 이름만 출이도록 하자.
unique_cands = fec.cand_nm.unique()

# 아까 맵핑해논 정당과 한번 연결해보도록 하자
fec.cand_nm[1:5].map(parties)

1 Republican
2 Republican
3 Republican
4 Republican
Name: cand_nm, dtype: object

공화당 놈들만 나오는구먼.

이제 정당 컬럼도 추가해보자

fec['party'] = fec.cand_nm.map(parties)
fec.ix[1]

cmte_id C00458844
cand_id P60006723
cand_nm Rubio, Marco
contbr_nm HEFFERNAN, MICHAEL
contbr_city APO
contbr_st AE
contbr_zip 090960009
contbr_employer INFORMATION REQUESTED PER BEST EFFORTS
contbr_occupation INFORMATION REQUESTED PER BEST EFFORTS
contb_receipt_amt 210
contb_receipt_dt 27-JUN-15
receipt_desc NaN
memo_cd NaN
memo_text NaN
form_tp SA17A
file_num 1029436
tran_id SA17.796904
election_tp P2016
party Republican
Name: 1, dtype: object

정당이 정상적으로 추가되었다.

자 그럼 어느 정당에 더 기부자들이 많을까?

fec['party'].value_counts()

Republican 226639
Democratic 158246
Name: party, dtype: int64

쪽수 만큼이나 많은 기부자들을 보유하고 있다.

그 다음 데이터를 다듬어 보도록 하자. 기부금과 환급금이 표시되어 있는데, 환급금의 경우 기부금이 마이너스다.
이경우는 제외하고 데이터를 만들어보자.

fec = fec[fec.contb_receipt_amt > 0]

자, 이제 본격적인 분석에 나서보곘다. 직업별로 기부한 사람들을 쭉 나열해보자.

fec.contbr_occupation.value_counts()[:5]

RETIRED 95257
NOT EMPLOYED 22636
INFORMATION REQUESTED PER BEST EFFORTS 14053
ATTORNEY 13030
HOMEMAKER 9944
Name: contbr_occupation, dtype: int64

Homemaker는 무슨직업이지…….? 주부인가?

자, 그럼 어떤 직업이 가장 많은 기부금을 냈을까?

fec.groupby('contbr_occupation').sum('contb_receipt_amt')
result = pd.DataFrame(sum_order)
result.sort_values('contb_receipt_amt', ascending=False)

contbr_occupation contb_receipt_amt
RETIRED 24398578.55
ATTORNEY 12236210.01
HOMEMAKER 9817525.21
INFORMATION REQUESTED PER BEST EFFORTS 6590687.40
CEO 5449444.47

은퇴한 아재들..

근데 데이터를 잘보면 직업들이 데이터가 이상하다. #1 Donald Trump.. 라는 놈도 있고
비슷하게 retired인데 다르게 쓴애들 이 있다. 이게 막 사용자들이 입력가능하게 한 값이라 그런 것 같다.
데이터를 비슷하게 맞춰보겠당.

occ_mapping = {
    'INFORMATION REQUESTED PER BEST EFFORTS' : 'NOT PROVIDED'
    , 'INFORMATION REQUESTED' : 'NOT PROVIDED'
    , 'INFORMATION REQUESTED (BEST EFFORTS)' : 'NOT PROVIDED'
    , 'C.E.O.' : 'CEO'
}


f = lambda x: occ_mapping.get(x, x)
fec.contbr_occupation = fec.contbr_occupation.map(f)

emp_mapping = {
    'INFORMATION REQUESTED PER BEST EFFORTS' : 'NOT PROVIDED'
    , 'INFORMATION REQUESTED' : 'NOT PROVIDED'
    , 'SELF' : 'SELF-EMPLOYED'
    , 'SELF EMPLOYED' : 'SELF-EMPLOYED'
}    

f = lambda x: emp_mapping.get(x, x)
fec.contbr_employer = fec.contbr_employer.map(f)

자 이제 직업별 기부 통계를 내보겠습니다!!

by_occupation = fec.pivot_table('contb_receipt_amt', index='contbr_occupation', columns='party', aggfunc=sum)
# 백만불이상만
over_1m = by_occupation[by_occupation.sum(1) > 1000000]
over_1m.plot(kind='barh')

donation1

우리 모두가 잘 알고 있는 대로, 기업인과 은퇴 아재들은 공화당을, 변호사들은 민주당을 좋아한다.

민주당 유력후보는 클린턴힐러리, 공화당 유력후보는 도널드트럼프다.
이 두 후보에게 많이 기부한 직업을 알아보자.
여담이지만 AWS 에 올려서 하니까 속도가 짱짱맨이다. 이 쯤 됐으면 내 노트북(그노트북말고)은 버벅거렸을 텐데.. AWS 차냥해!

def get_top_amounts(group, key, n=5):
    totals = group.groupby(key)['contb_receipt_amt'].sum()
    return totals.order(ascending=False)[:n]

fec_vs2 = fec[fec.cand_nm.isin(['Clinton, Hillary Rodham', 'Trump, Donald J.'])]
grouped = fec_vs2.groupby('cand_nm')
grouped.apply(get_top_amounts, 'contbr_occupation', n=5)

cand_nm                  contbr_occupation
Clinton, Hillary Rodham  ATTORNEY             7146133.33
                         RETIRED              5254984.82
                         HOMEMAKER            2679508.43
                         CONSULTANT           2104574.24
                         LAWYER               1992587.86
Trump, Donald J.         RETIRED               267596.02
                         EXECUTIVE             109646.15
                         OWNER                  50672.09
                         CEO                    46839.45
                         PRESIDENT              37676.37

역시 트럼프아재는 기업인들에게 사랑받고 있었다.

이번엔 금액대별로 분석을 해보겠다.
단순히 기부금액만으로 그사람의 인기를 판단하는 건 섣부른일 일 것이다.

# 금액대 별로 Array를 만든다.
bins = np.array([0, 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000])
# panda cut 함수를 이용하여 기부 규모별로 나누고
labels = pd.cut(fec_vs2.contb_receipt_amt, bins)
# 다시 그룹핑한다.
grouped = fec_vs2.groupby(['cand_nm', labels])
# 그리고 총사이즈 별로 나눈다.
grouped.size().unstack(0)

cand_nm Clinton, Hillary Rodham Trump, Donald J.
contb_receipt_amt
(0, 1] 423 NaN
(1, 10] 7682 9
(10, 100] 33080 398
(100, 1000] 22492 1730
(1000, 10000] 19461 136
(10000, 100000] 1 1

 

여담이지만 도널드 트럼프에 8.7만달러 기부한 아재가 있다.

Trump, Donald J. BOCH, ERNIE NORWOOD MA 02062 BOCH AUTOMOTIVE GROUP EXECUTIVE 86936.80

자동차 딜러하는 아조씨다.

bucket_sums = grouped.contb_receipt_amt.sum().unstack(0)

cand_nm Clinton, Hillary Rodham Trump, Donald J.
contb_receipt_amt
(0, 1] 406.71 NaN
(1, 10] 56368.03 90.00
(10, 100] 1899566.88 27512.25
(100, 1000] 10273412.25 626352.36
(1000, 10000] 50397748.13 376526.52
(10000, 100000] 20000.00 86936.80

역시 도널드트럼프에게 1달러 이하로 기부하는 놈들은 없다.

 

이제 정규화해서 그래프로 아름답게 만들어 보겠다.

normed_sums = bucket_sums.div(bucket_sums.sum(axis=1), axis=0)
normed_sums.plot(kind='barh', stacked=True)

donation2

마지막으로 주별 기부 통계를 내보고 끝내야겠다.

# 정당과 주별로 그룹핑하고
grouped = fec.groupby(['party', 'contbr_st'])
# 이에 대한 총합을 구한다.
totals = grouped.contb_receipt_amt.sum().unstack(0).fillna(0)
# 총합이 10만불인 데이터만 본다.
totals = totals[totals.sum(1)>100000]
totals[:10]

 

party Democratic Republican
contbr_st
AK 66243.38 111684.23
AL 153896.42 871322.34
AR 565954.43 933845.22
AZ 430958.60 1460142.41
CA 16197087.78 11994519.37
CO 1607373.34 1366675.87
CT 1379328.28 1704919.35
DC 3450931.43 1135268.23
DE 61785.81 115208.74
FF 0.00 113470.00

주별로 전체기부금액을 나눠버리면, 퍼센트로도 볼 수 있을 것이다.

percent = totals.div(totals.sum(1), axis=0)
percent[:10]

party Democratic Republican
contbr_st
AK 0.372305 0.627695
AL 0.150111 0.849889
AR 0.377353 0.622647
AZ 0.227888 0.772112
CA 0.574536 0.425464
CO 0.540466 0.459534
CT 0.447217 0.552783
DC 0.752460 0.247540
DE 0.349083 0.650917
FF 0.000000 1.000000

 

 

다음엔 AWS 에 ipython notebook을 어떻게 올렸는지 얘기해보도록 하자.

[Python] 미국 신생아 이름 분석

미국에서 한해 동안 태어난 신생아의 이름을 분석해보았다.
출처는 미국 사회보장국 (SSA, Social Security Administration) 이다.

일단 파일은 여기 에서 구할수 있다.

데이터는 Mary,F,7065 이런 식으로 구성되어 있다. 시작해보자.

import pandas as pd
import numpy as np
names1880 = pd.read_csv('C:\\Users\\SS\\Desktop\\NewbornNames\\names\\yob1880.txt', names=['name', 'sex', 'birhts'])

대략 이런식의 결과물이 나온다. Mary가 엄청유행했다는 얘기다.

name sex birhts
0 Mary F 7065
1 Anna F 2604
2 Emma F 2003
3 Elizabeth F 1939
4 Minnie F 1746
5 Margaret F 1578
6 Ida F 1472
7 Alice F 1414
8 Bertha F 1320
9 Sarah F 1288
10 Annie F 1258

자료가 1880년~2014년 까지 있다. 모든 데이터를 하나로 취합하고, Year 항목을 추가한 DataFrame을 만들어보겠다.

# 범위 설정
years = range(1880, 2014)

# 컬럼과 합칠 list 설정
pieces = []
columns = ['name', 'sex', 'births']

for year in years:
    #데이터를 한번 읽어온 다음, frame에 넣는다.
    path = 'C:\\Users\\SDS\\Desktop\\NewbornNames\\names\\yob%d.txt' % year
    frame = pd.read_csv(path, names=columns)
    
    #frame에 년도를 넣어두고
    frame['year'] = year
    #리스트에 frame을 집어넣는다.
    pieces.append(frame)

# 마지막으로 다 합친다.
names = pd.concat(pieces, ignore_index=True)

그 결과

name sex births year
0 Mary F 7065 1880
1 Anna F 2604 1880
2 Emma F 2003 1880
3 Elizabeth F 1939 1880
4 Minnie F 1746 1880
5 Margaret F 1578 1880
6 Ida F 1472 1880
7 Alice F 1414 1880
8 Bertha F 1320 1880
9 Sarah F 1288 1880
10 Annie F 1258 1880

그렇게 의미있는 데이터는 아니다. 연도별로 출생수가 다 따로 있기 때문이다. 이 데이터를 기반으로 각 연도, 성별로 몇명이 출산했는지 pivot으로 알아보도록 하겠다.


# Birth를 기준으로, index(row)는 year, column은 sex, 그리고 총누계를 구한다.
total_births = names.pivot_table('births', index='year', columns='sex', aggfunc=sum)

sex F M
year
1880 90993 110491
1881 91954 100745
1882 107850 113688
1883 112321 104629
1884 129022 114445
1885 133055 107800
1886 144535 110784
1887 145982 101414
1888 178627 120853
1889 178366 110584
1890 190377 111025
1891 185482 101196
1892 212346 122037
1893 212906 112317
1894 222922 115772

정렬을 할 수도 있을 것이다. 하지만 정렬은 생략하겠다. 이제 다음으로는, Prop열을 추가해서 전체출생수에서 이름이 차지하는 비율을 계산해보도록 하겠다.


def add_prop(group):
 #births를 실수형 타입으로 선언
 births = group.births.astype(float)
 
 #나눈당
 group['prop'] = births / births.sum()
 return group

names = names.groupby(['year', 'sex']).apply(add_prop)

물론 제대로 나왔겠지만, Sanity check을 해보자.

  np.allclose(names.groupby(['year', 'sex']).prop.sum(), 1)

근데 데이터가 너무 많다. 그래서 연도별, 성별에 따라 빈도수가 가장 높은 이름만 2000개 추출해보도록 하겠다.

pieces = []

for year, group in names.groupby(['year', 'sex']):
 pieces.append(group.sort_values(by='births', ascending=False)[:2000])
 
top2000 = pd.concat(pieces, ignore_index=True)

name sex births year prop
0 Mary F 7065 1880 0.077643
1 Anna F 2604 1880 0.028618
2 Emma F 2003 1880 0.022013
3 Elizabeth F 1939 1880 0.021309
4 Minnie F 1746 1880 0.019188
5 Margaret F 1578 1880 0.017342
6 Ida F 1472 1880 0.016177
7 Alice F 1414 1880 0.015540
8 Bertha F 1320 1880 0.014507
9 Sarah F 1288 1880 0.014155
10 Annie F 1258 1880 0.013825

boys = top2000[top2000.sex == 'M']
girls = top2000[top2000.sex == 'F']

몇몇 이름들의 추세를 그래프로 표시해볼 수 있다.
아까 만들었던 Pivot_table은 연도, 성별 기준이므로, 이름 기준을 하기위해서는 pivot을 좀 가공해야한다.


total_births = top2000.pivot_table('births', index='year', columns='name', aggfunc=sum)

이제 그래프를 그려보자.

%matplotlib inline
import matplotlib.pyplot as plt

subset = total_births[['John', 'Harry', 'Mary', 'David']]
subset.plot(subplots=True, figsize=(12, 10), grid=False)

plt1

흔히들, 많이 쓰는 이름들은 부모들이 지을 때 기피하는 경향이 있을 것이라고 생각한다.  과연 그럴까?

상위 이름 2000개가 전체 이름 중에서 차지하는 비율을 계산해보면 알 수 있을 것 같다.


table = top2000.pivot_table('prop', index='year', columns='sex', aggfunc=sum)

table.plot(yticks=np.linspace(0, 1.2, 13), xticks=range(1880, 2020, 10))

plt2

상위 2000개의 이름이 차지하는 비중이 점점 낮아지는 것을 볼수가 있다.

 

이번에는 prop를 내림차순으로 정렬하고, 그 합이 50%가 될때까지 얼마나 많은 이름들이 등장하는지 알아보겠당.

def get_quantile_count(group, q=0.5):
   # Group을 Porp순으로 내림차순 정렬한다.
   group = group.sort_values(by='prop', ascending=False)
   # 0.5가 될 때까지 누적에서 더한 횟수를 리턴한다. (0부터 시작이라 1을 더했다)
   return group.prop.cumsum().searchsorted(q) + 1

diversity = top2000.groupby(['year', 'sex']).apply(get_quantile_count)
diversity = diversity.unstack('sex')

# python 2.x 버전에서는 실수형으로 맞춰줘야 한다 ㅠㅠㅠ
diversity = diversity.astype(float)

시간이 지날수록 전체 이름 개수의 50%를 차지하기위해서 등장하는 이름이 많아지는 것을 볼 수 있다.

plt3

이름의 마지막 글자가 어떻게 변화했는지 살펴보자
람다식을 사용했다.

get_last_letter = lambda x: x[-1]
last_lettrers = names.name.map(get_last_letter)
last_lettrers.name = 'last letter'

table = names.pivot_table('births', index=last_lettrers, columns=['sex', 'year'], aggfunc=sum)

sex F M
year 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013
last letter
a 31446 31581 36536 38330 43680 45408 49100 48942 59441 58632 38673 36877 36210 34723 32988 31573 28814 27384 27136 27299
b NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN 45939 43178 42645 42190 40047 39038 39208 36605 34626 33089

그 다음, 전체 출생수에서 성별로 각각의 마지막 글자가 차지하는 비율을 계산하기 위해 전체 출생수로 정규화 해보겠당.

#테이블 데이터의 년도를 한정시킨다.
subtable = table.reindex(columns=[1910, 1960, 2010], level='year')
#마지막 글자의 비율을 계산한다.
letter_prop = subtable / subtable.sum().astype(float)
#그래프를 그린다
fig, axes = plt.subplots(2, 1, figsize=(10, 8))
letter_prop['M'].plot(kind='bar', rot=0, ax=axes[0], title='Male', legend=False)
letter_prop['F'].plot(kind='bar', rot=0, ax=axes[1], title='Female', legend=False)

plt4

그렇다면, 특정 글자로 끝나는 남자아이의 이름 비율이 어떻게 될까?

letter_prop = table / table.sum().astype(float)
dny_ts = letter_prop.ix[['d', 'n', 'y'], 'M'].T
dny_ts.plot()

plt5

d로 끝나는 남자아이의 이름이 미친듯이 증가하고 있다.

자 이제 마지막이다. 남녀 이름이 요즘은 비슷한 경우가 많은데, 그 경우는 어떨까?
lesl이 들어있는 이름이 남녀 구분하고 많다고 한다.

# 괄호가 빠져버리면 List가 안된다. 주의하자.
# Unique한 이름만 가져온다.
all_names = top2000.name.unique()
# for문을 돌면서 lesl이 들어있는 이름들을 mask에 넣는다.
mask = np.array(['lesl' in x.lower() for x in all_names])
# lesl가 들어간 애들만 따로 추린다.
lesl_like = all_names[mask]
# top2000이름에서 또 저것만 있는 것을 필터링한다.
filtered = top2000[top2000.name.isin(lesl_like)]
# 이름으로 그룹핑하고 총합계를 구한다.
filtered.groupby('name').births.sum()
# pivot 테이블
table = filtered.pivot_table('births', index='year', columns='sex', aggfunc=sum)
# 누적을 1기준으로 나눈다.
table = table.div(table.sum(1), axis=0)
# 그래프를 그린다.
table.plot(style={'M': 'k-', 'F':'k--'})

plt6

다음시간에 또 만나요~~~