필요한 패키지 import

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


csv 파일 읽어오기 by Pandas

battles = pd.read_csv( "data/game-of-thrones/battles.csv", sep=",")
death = pd.read_csv( "data/game-of-thrones/character-deaths.csv", sep=",")

battles라는 DataFrame 에는 전투 데이터 관련이,
deaths 에는 모든 등장인물의 등장정보와 사망년도/사망장소에 관련 정보가 있다.


데이터 확인하기

battles.shape
battles.head()
battles.columns
image

image

* 데이터.columns를 하면 컬럼명들이 리스트형식으로 반환된다.


데이터 분석하기(1)

1. 전체기준열의 각 values값이 포함된 행수의 세기(분포) => 라인플롯 그리기
파읽 읽기 –> shape / head() / columns(칼럼명들만 리스트로 반환) 보기 –>  전체 기준열을 인덱싱한 뒤, .value_counts()로 포함된 행수를 Series로 받기 –>  그 Series의 분포에, .sort_index()를 통해 오름차순 정리하기 –>  새로운 변수에 담아서, 변수.plot()그리기 –> plot그릴 때 반환 받은 axes변수로 xticks(yticks) 정수로 바꿔주기 –> xlim(ylim)으로 범위 늘려주기

image

첫 번째로, deaths라는 데이터프레임에서 죽은 책의 이름을 의미하는 [ 죽은책 번호(Book of Death)에 따른 –> 죽은사람의 명수(행의 수=사람의 수)를  ] 시각화해보자.  즉, 전체기준열의 각 values값이 포함된 행수의 분포를 보면 된다.
- 각 행이 한 사람을 의미하므로, value_counts()로 세어진 행수 = 사람의 수를 의미하게 된다.

  1. book_nums_to_death_count = deaths["Book of Death"].value_counts().sort_index() 를 통해
    기준열(책 번호-Book of Death)에 따른 죽은 인물들의 명수를 구하여 –> book_nums_to_death_count 변수에 담는다.
    (13강. sort_index()는 열인덱싱을 통해 시리즈로 나타날 데이터의 index를 오름차순으로 만들어준다)
    1편에서는 49명이 죽었고, 2편에서는 73명이 죽었고… 를 한눈에 알 수 있다.
    image


라인플롯 그리고 보기 편하게 변형하기

  1. fig없이 바로 데이터.plot()함수를 이용해, 해당 데이터로 라인플롯을 그린다.
    color, marker, linestyle을 인자로 함께 주면서,  데이터.plot()으로 그린 좌표평면을 반환 받는다.
    ax1 = book_nums_to_death_count.plot( color ="k", marker = "o", linestyle = "—")
    image

  2. 1.0부터 5.0로 소수점까지 포함된 xtick을, 정수로 바꿔주기 위해서  좌표평면.set_xticks()함수에 np.arange(1,6)을 이용한다
    ax1.set_xticks(np.arange(1,6))
    image

  3. x축의 범위를 조금 늘려 0부터 6까지 나타내기 위해서
    ax1.set_xlim( [0,6] )
    image
  4. y축은 정수니까, 범위만 조금 늘려준다.
    image

데이터를 시각화해서 보니, 3권에서 가장 많은 사람이 죽었다는 것을 알 수 있다.


image





데이터 분석(2)

2. index를 name열로 바꾼 뒤, 각 name행에 따른 조건을 만족하는 특정열 1,2를 뽑고-> 특정열 1,2의 비율 비교하기
name열을 데이터프레임.set_index( [칼럼명] )을 통해  새로운index 만들기 –> 특정열1과 특정열2를 인덱싱하여 합이 10000이 넘도록 조건문을 달아 새로운 boolean마스크 변수 생성-> 마스크변수를 행인덱스에 집어넣고, 뽑아낼 특정열1,2를 열인덱싱에 넣어, 해당조건을 만족하는 행 뽑아낸 뒤 새로운 DataFrame변수에 집어넣기 –> 새로운 DataFrame으로 plot()을 stacked옵션을 주어서  만들기 –> 각 비율을 계산한 열을 추가로 생성하여, 비율 열1,2로 효과적인 비율 비교의 bar플롯 그리기

image


battles에 대한 데이터를 다시 한번 확인하기 위해 .head()를 확인한다.
image

battles 데이터에서는 전투군과 수비군에 대한 정보가 서술되어있다.

공격군과 수비군의 수(attacker_size, defender_size)의 합이 10,000이상되는 대규모 전투를 뽑은 뒤, 
대규모 전투 별로 병력차이를 비교해보고  Boxplot(수평barh+stacked)으로 시각화 해보자.

  1. 단순히 0부터 정수로 되어있는 index를 전투의 이름(name)으로 바꾼 뒤, battels에 대입하여 덮어씌우자.
    battles = battles.set_index(["name"])
    battles.head()
    image
  2. 공격군과 수비군의 합이 10000만 이상 되는 것을 뽑기 위해, 해당조건으로 boolean마스크를 생성한 뒤 변수에 담아준다.
    large_battles_mask = battles["attacker_size"] + battles["defender_size"] > 10000
    image
  3. 마스크로 행인덱싱 하고, 확보할 열 2개(공격군, 수비군 수)을 열인덱싱하여, 조건에 맞는 행만 뽑아낸 뒤,  새로운 데이터프레임에 담는다.
    large_battles = battles.loc[large_battles_mask, ["attacker_size", "defender_size"]]
    large_battles.head()
    image

  4. 이제 대규모전투만 뽑은 DataFrame에 대해, 각 군의 상대적인 비율을 확인하기위해 bar플롯(수평barh + stacked)을 그려보자.
    large_battles.plot(kind="barh", stacked=True , fontsize = 8)
    image
    공격군+수비군의 합이 만명이 넘어가는 대규모 전투는 총 10개가 있었고,
    bar플롯(stacked)을 통해 병력차이를 확인할 수 있다.

  5. 공격군과 수비군의 효과적인 비율비교를 위해서,  비율을 먼저 계산하여 새로운 열로 추가하고,  bar플롯으로 그려보자.
    비율로 계산하면,, 수평bar+stacked로 바플롯을 그리면, 수평막대를 완전히 채울 수 있다.(2개의 합 = 1)
    large_battles["attacker_pcts"] = large_battles["attacker_size"] / ( large_battles["attacker_size"] + large_battles["defender_size"] )
    새로운 열은  공격군 / (공격군 + 수비군의 합) 으로 계산된 공격군의 비율이다. 수비군의 비율도 유사하게 추가해준다.
    large_battles["defender_pcts"] = large_battles["defender_size"] / ( large_battles["attacker_size"] + large_battles["defender_size"] )
  6. 각 비율 열 2개만 인덱싱하여 barplot을 그려보자.
    ax3 = large_battles[ ["attacker_pcts" , "defender_pcts"] ].plot( kind = "barh", stacked = True, fontsize = 8)image







데이터 분석(3)

3. 여러개의 특정열의 values를  Series의 index로 만들고,  그 각각의 values가 여러개의 특정열에 포함된 행의 수를 뽑아내서 히스토그램 만들기
여러개의 특정열을 관리하기 쉽게 칼럼명만 칼럼인덱싱으로 뽑아내서 변수에 담기 –> 여러개의 특정열에 나타는 values중에 NaN이 포함된 것을 none문자열으로 치환한 뒤, np.unique()로 중복없는 values리스트들을 새로운 변수에 담기-> 중복없는 values리스트를 index로 준 빈 Series 만들기 –> for문을 통해, 여러개의 특정열 칼럼명 변수를 통해 하나씩 순회하면서, 각 열에 value_counts()를 통해  각 value가 포함된 행수를 빈 Series에 .add()하기 +  fill_value = 0 으로 특정열 속의 NaN은 0으로 계산해서 더하기 –> 히스토그램 그리기
image


각의 가문들(attacker_1~4, defender_1~4에 속한 values값들)이 전투에 몇회 참여했는지 를 분석하고, 히스토그램으로 나타내보자.
image

  1. 컬럼 중에 전투에 참여한 가문들이 나와있는 <컬럼명> 발췌해보자.  ( .columns –>칼럼명 리스트 / .columns[ a:b] –> 일부 칼럼명 리스트)
    *** 칼럼명들만 모아서 가지고 열인덱싱[칼럼명들 변수]로 손쉽게 인덱싱할 수 있다. 원래는 필요한 열들만 발췌해야하나, NaN이 껴있기때문에, 필요한 열들의 칼럼명을 뽑아서 다른 처리를 먼저 해줘야하기 때문이다.
    이 때, 컬럼들이 붙어 있으므로 <컬럼명>열 번호로 인덱싱한 뒤, 컬럼 명 변수에 담아서 확인해보자.(5번째 열부터 12번째 열까지 총 8개)
    (cf. battles[4:12]면 열 인덱싱이고 , battles.columns[4:12]는 컬럼명만 가져온다.
    col_names = battles.columns[4:12]
    col_names
    image
  2. 참여가문들이 나와있는 8개 열에 대한 중복없는 <unique한 가문의 이름=value>들만 뽑아야한다. 하지만 데이터를 보면, NaN 값이 있다.
    NaN을 포함하고 있을 때에는 unique()로 뽑을 때 오류가 나므로, 먼저 NaN부터 다른 문자열(“none”)으로 채운 뒤, none을 제거하는 방식으로 가야한다.
    열인덱싱 할 때, 뽑아놓은 컬럼명을 대입하여, 그것만 열인덱싱한 상태에서, NaN값을 “None”으로 채운 뒤, value(값)들만 새로운 변수에 담자. 그러면 8개열의 모든 value들(중복포함)이 각 열별로 NaN없이 담길 것이다.
    (여러개의 열인덱싱.values를 하면, 각 열별로 values들이 담긴다)
    열별로, 각 values들이 담긴 것을, [:5]를 통해, 5열만 살펴보자.
    house_names = battles[col_names].fillna("None").values
    house_names[:5]
    image
    여러개의 열들을 인덱싱한 뒤, .vaules로 값들을 넣으면 각 열에 대한 values들이 2차원 array로 얻어지는 것을 확인할 수 있다.
    각 열에 대한 values들만 각 열별로 나누어 담기 때문에, index같은 것은 없다.
  3. numpy에서 제공하는 unique()함수를 적용해서, 다시 담아넣자.
    np.unique()함수를 쓰면, 각 열별로 value값들이 2차원 array형태를 가졌는데, 1xn의 1차원 array 중복없이 싹다 모아버린다.
    house_names = np.unique(house_names)
    house_names
    image

  4. 간편하게 none을 제거하기 위해서, 열인덱싱(1차원에서는 n번째 성분을 의미!)으로 boolean마스크를 이용해서,
    성분들 중에 None이 아닌 것만 담도록 인덱싱해서 다시 담아준다. 즉, 성분(각 열로 취급)들 중에 None이 아닌 모든 것들을 인덱싱하는 것이다.
    house_names = house_names[house_names != "None"]
    house_names
    image
    NaN이 제거된 순수한 가문들(8개열의 values)들을 얻을 수 있다.
    해석하자면, 최소 1회 전투에 참여한 모든 가문들의 이름을 모은 것이다.


  5. 이제 위의 가문들을 index로 하고, 성분은 0으로 하는 Series를 하나 정의하자.
    최종 목표인 <가문을 index로 하여, 각 가문에 따른 전투 참여 횟수>의 Series를 만들기 위한 준비이다.
    ( data에 0만 넣으면 모든 index에 대해서 0으로 찍히는 Series가 만들어진다)
    house_to_battle_counts = pd.Series(0, index = house_names)
    house_to_battle_counts
    image
    여기에, 각 열을 기준으로 index에 합산되도록 해서, 전투 참여횟수를 구할 수 있다.
  6. 만들어진  가문이름을 index로 한 Series에다가, 
    battles의 열인 attacker_1부터 4까지, defender_1부터 4까지 순회하면서 등장하는 가문이름이 포함된 행의 수를 .value_counts()를 통해 Series형태로 얻은 다음 대입해준다. 이렇게 Series로 계산하는 이유는, 열을 인덱싱해서 얻어지는 Series의 경우 .value_counts()를 하게 되면, 각 가문을 의미하는 value값을 가지는 행들의 갯수 [values값(가문이름) – 해당 횟수]의 Series형태로 뽑히기 때문이다.
    그래서 만들어둔 빈 Series인 house_to_battles_counts에 .add( Series형태 ) 하게 되면, 더해질 value값과 가문이름이 동일한 곳에 해당 횟수가 더해지진다.
    순회는 for문을 통해서 이미 만들어둔, col_names를 가지고 하나씩 대입해서 순회한다.
    이 때, Series.add ( Series )의 인자에 추가로, fill_value=0를 넣어 순회하는 8개의 특정열에 포함된 NaN은 0으로 치환해서 add해주게 한다.
         참고)  battles["attacker_1"].value_counts()
         image
    for col in col_names :
         house_to_battle_counts = house_to_battle_counts.add( battles[col].value_counts() , fill_value = 0)
    image
    총 8개의 열에서, 각 가문이 몇번 등장했는지, 데이터가 나오게 된다.

    해석해보자면,  Lannister가문과 Stark가문이 다른가문에 비해 압도적으로 많이 전투에 참여했다는 것을 알 수 있다.
  7. 이제 이 데이터로 히스토그램을 그려보자.
    ax4 = house_to_battle_counts.hist(bins=10)
    image
    해석)
    대체로 1회~ 3회 정도까지 전투에 개입한 가문이 제일 많고 , 15~18회 전투를 참여한 가문은 1번으로 드물다.

+ Recent posts