사람들의 일자리를 만들어 기업체를 운영한다는 것은 아주 어려운 일이다. 코로나로 일자리 파이가 쪼그라드는 이 시점에는 사업의 흥망에 대해 낙관적인 전망을 기대하기는 어렵다.
어려운 상황임에도 불구하고, 수십년간 많은 사람들의 일자리를 챙겨온 대단한 인물이 있다.
비주기, 상록시티의 관장이자, 1996년 2월 27일부터 20년 넘게 로켓단을 이끌어 오고 있는 인물이다.
그를 서술 하고 있는 작중 행적에 따르면, 그의 목표는 돈과 포켓몬에 의한 세계정복이다. 때문에 강한 포켓몬들을 모으는 것이 주로 하는 일이라 밝히고 있다. 정리하자면, 돈과 세계정복을 위해 로켓단이라는 전국적인 기업을 만들어 일자리를 창출해왔고, 피고용인들로 하여금 강한 포켓몬을 수집하고 있는 것이었다.
이런 목표로 움직이고 있는 로켓단인데, 왜 우리들의 기억에 남아있는 로켓단은 약한 모습인 걸까?
1import numpy as np
2import pandas as pd
3import seaborn as sns
4
5%matplotlib inline
6import random
7
8random.seed(1)
9
10# 포켓몬 정보를 불러와보자
11pokemon = pd.read_csv("./input/pokemon.csv")
12pokemon.head()
# | Name | Type 1 | Type 2 | HP | Attack | Defense | Sp. Atk | Sp. Def | Speed | Generation | Legendary | |
0 | 1 | Bulbasaur | Grass | Poison | 45 | 49 | 49 | 65 | 65 | 45 | 1 | False |
1 | 2 | Ivysaur | Grass | Poison | 60 | 62 | 63 | 80 | 80 | 60 | 1 | False |
2 | 3 | Venusaur | Grass | Poison | 80 | 82 | 83 | 100 | 100 | 80 | 1 | False |
3 | 4 | Mega Venusaur | Grass | Poison | 80 | 100 | 123 | 122 | 120 | 80 | 1 | False |
4 | 5 | Charmander | Fire | NaN | 39 | 52 | 43 | 60 | 50 | 65 | 1 | False |
1# 전투 정보를 불러와보자
2combat = pd.read_csv("./input/combats.csv")
3combat.head()
First_pokemon | Second_pokemon | Winner | |
0 | 266 | 298 | 298 |
1 | 702 | 701 | 701 |
2 | 191 | 668 | 668 |
3 | 237 | 683 | 683 |
4 | 151 | 231 | 151 |
1print("pokemon: " + str(pokemon.shape))
2print("combat: " + str(combat.shape))
3
4# 현재의 정보는 잘 불러와졌다.
5# pokemon: (800, 12)
6# combat: (50000, 3)
1combat.isnull().sum()
2# First_pokemon 0
3# Second_pokemon 0
4# Winner 0
5# dtype: int64
6
7pokemon.isnull().sum()
8# 0
9# Name 1
10# Type 1 0
11# Type 2 386
12# HP 0
13# Attack 0
14# Defense 0
15# Sp. Atk 0
16# Sp. Def 0
17# Speed 0
18# Generation 0
19# Legendary 0
20# dtype: int64
21
1print("==== Name = NaN, 누구냐 넌 ==== ")
2
3if pokemon[pokemon['Name'].isnull()].size != 0:
4 who = pokemon[pokemon['Name'].isnull()]
5 print(who, '\n')
6
7 print('앞 포켓몬 : ', pokemon['Name'][int(who.index[0])-1])
8 print('뒤 포켓몬 : ', pokemon['Name'][int(who.index[0])+1])
9 pokemon[pokemon['#'] == 63]
10else:
11 print("이름이 비어있는 포켓몬이 없습니다.")
12
13==== Name = NaN, 누구냐 넌 ====
14앞 포켓몬 : Mankey
15뒤 포켓몬 : Growlithe
도감에 따르면, 망키와 가디 사이에는 성원숭이 있다. Type 1이 Fighting인 것을 보면 성원숭이 확실할 것이다. 성원숭의 값을 정확하게 채워주자.
# | Name | Type 1 | Type 2 | HP | Attack | Defense | Sp. Atk | Sp. Def | Speed | Generation | Legendary | |
62 | 63 | Primeape | Fighting | NaN | 65 | 105 | 60 | 60 | 70 | 95 | 1 | False |
1totalWins = combat.Winner.value_counts() # 전체 승리
2countWins = combat.groupby('Winner').count()
3
4countFirst = combat.groupby('First_pokemon').count()
5countSecond = combat.groupby('Second_pokemon').count()
6
7print("Count by first winner shape: " + str(countFirst.shape))
8print("Count by second winner shape: " + str(countSecond.shape))
9print("Total Wins shape : " + str(totalWins.shape))
10
11Count by first winner shape: (784, 2)
12Count by second winner shape: (784, 2)
13Total Wins shape : (783,)
1find_pokemon= np.setdiff1d(countFirst.index.values, countWins.index.values)-1
2found = pokemon.iloc[find_pokemon[0],]
3print(found)
4
5# 231
6Name Shuckle
7Type 1 Bug
8Type 2 Rock
9HP 20
10Attack 10
11Defense 230
12Sp. Atk 10
13Sp. Def 230
14Speed 5
15Generation 2
16Legendary False
17Name: 230, dtype: object
해당 전투 데이터에서 단단지는 한번도 승리하지 못했다고 한다. 실제로 그렇게 약한지는 잘 기억이 나지 않는다. 결론이 나온 것은 아니지만, 일단 로켓단은 단단지를 다루지 않으면 된다는 단서를 하나 얻었다.
그러나 이 글은 로켓단에게 전하는 컨설팅이다.
포켓몬 세계관 중 현실과의 중요한 매개체가 되는 포켓몬GO에 이르러서는 단단지가 로켓단의 주축이 된 적이 있다. 로켓단이 왜 약한가? 약한 친구를 데리고 다니기 때문이다 😭😭 https://pokemongolive.com/post/gofestweeklychallenge-teamgorocket/?hl=ko
1numberOfWins = countWins.sort_index()
2numberOfWins['Total Fights'] = countFirst.Winner + countSecond.Winner
3numberOfWins['Win Percentage']= numberOfWins.First_pokemon/numberOfWins['Total Fights']
4
5mergedResult = pd.merge(pokemon, numberOfWins, left_on='#', right_index = True, how='left')
1mergedResult[np.isfinite(mergedResult['Win Percentage'])].sort_values(by = ['Win Percentage']).head(10)
# | Name | Type 1 | Type 2 | HP | Attack | Defense | Sp. Atk | Sp. Def | Speed | Generation | Legendary | First_pokemon | Second_pokemon | Total Fights | Win Percentage | |
289 | 290 | Silcoon | Bug | NaN | 50 | 35 | 55 | 25 | 25 | 15 | 3 | False | 3.0 | 3.0 | 138.0 | 0.021739 |
189 | 190 | Togepi | Fairy | NaN | 35 | 20 | 65 | 40 | 65 | 20 | 2 | False | 3.0 | 3.0 | 122.0 | 0.024590 |
638 | 639 | Solosis | Psychic | NaN | 45 | 30 | 40 | 105 | 50 | 20 | 5 | False | 4.0 | 4.0 | 129.0 | 0.031008 |
236 | 237 | Slugma | Fire | NaN | 40 | 40 | 40 | 70 | 40 | 20 | 2 | False | 4.0 | 4.0 | 123.0 | 0.032520 |
576 | 577 | Munna | Psychic | NaN | 76 | 25 | 45 | 67 | 55 | 24 | 5 | False | 5.0 | 5.0 | 128.0 | 0.039062 |
188 | 189 | Igglybuff | Normal | Fairy | 90 | 30 | 15 | 40 | 20 | 15 | 2 | False | 5.0 | 5.0 | 115.0 | 0.043478 |
394 | 395 | Wynaut | Psychic | NaN | 95 | 23 | 48 | 23 | 48 | 23 | 3 | False | 6.0 | 6.0 | 130.0 | 0.046154 |
209 | 210 | Wooper | Water | Ground | 55 | 45 | 45 | 25 | 25 | 15 | 2 | False | 6.0 | 6.0 | 125.0 | 0.048000 |
291 | 292 | Cascoon | Bug | NaN | 50 | 35 | 55 | 25 | 25 | 15 | 3 | False | 7.0 | 7.0 | 133.0 | 0.052632 |
752 | 753 | Spritzee | Fairy | NaN | 78 | 52 | 60 | 63 | 65 | 23 | 6 | False | 8.0 | 8.0 | 133.0 | 0.060150 |
1mergedResult[np.isfinite(mergedResult['Win Percentage'])].sort_values(by = ['Win Percentage'], ascending = False ).head(10)
# | Name | Type 1 | Type 2 | HP | Attack | Defense | Sp. Atk | Sp. Def | Speed | Generation | Legendary | First_pokemon | Second_pokemon | Total Fights | Win Percentage | |
154 | 155 | Mega Aerodactyl | Rock | Flying | 80 | 135 | 85 | 70 | 95 | 150 | 1 | False | 127.0 | 127.0 | 129.0 | 0.984496 |
512 | 513 | Weavile | Dark | Ice | 70 | 120 | 65 | 45 | 85 | 125 | 4 | False | 116.0 | 116.0 | 119.0 | 0.974790 |
703 | 704 | Tornadus Therian Forme | Flying | NaN | 79 | 100 | 80 | 110 | 90 | 121 | 5 | True | 121.0 | 121.0 | 125.0 | 0.968000 |
19 | 20 | Mega Beedrill | Bug | Poison | 65 | 150 | 40 | 15 | 80 | 145 | 1 | False | 115.0 | 115.0 | 119.0 | 0.966387 |
153 | 154 | Aerodactyl | Rock | Flying | 80 | 105 | 65 | 60 | 75 | 130 | 1 | False | 136.0 | 136.0 | 141.0 | 0.964539 |
476 | 477 | Mega Lopunny | Normal | Fighting | 65 | 136 | 94 | 54 | 96 | 135 | 4 | False | 124.0 | 124.0 | 129.0 | 0.961240 |
726 | 727 | Greninja | Water | Dark | 72 | 95 | 67 | 103 | 71 | 122 | 6 | False | 122.0 | 122.0 | 127.0 | 0.960630 |
716 | 717 | Meloetta Pirouette Forme | Normal | Fighting | 100 | 128 | 90 | 77 | 77 | 128 | 5 | False | 118.0 | 118.0 | 123.0 | 0.959350 |
164 | 165 | Mega Mewtwo Y | Psychic | NaN | 106 | 150 | 70 | 194 | 120 | 140 | 1 | True | 119.0 | 119.0 | 125.0 | 0.952000 |
349 | 350 | Mega Sharpedo | Water | Dark | 70 | 140 | 70 | 110 | 65 | 105 | 3 | False | 114.0 | 114.0 | 120.0 | 0.950000 |
승패를 기준으로 포켓몬을 10마리씩 나열했다. 패배 기준으로는 전체적인 수치가 낮은 것을 확인할 수 있었고 승리 기준으로는 반대로 전반적인 수치가 고르게 높은 편이었다. 특이한 점은 전설 개체가 아니더라도 Mega 진화 개체가 다수 포함된 것을 확인할 수 있었다.
1import matplotlib.pyplot as plt
2ax = sns.countplot(x="Type 1", data=mergedResult)
3plt.xticks(rotation= 90)
4plt.xlabel('Type 1')
5plt.ylabel('Total ')
6plt.title("Pokemon MainType")
1ax = sns.countplot(x="Type 2", data=mergedResult)
2plt.xticks(rotation= 90)
3plt.xlabel('Type 2')
4plt.ylabel('Total ')
5plt.title("Pokemon SubType")
1mergedResult.groupby('Type 1').agg({"Win Percentage": "mean"}).sort_values(by = "Win Percentage")
Win Percentage | |
Type 1 | |
Fairy | 0.329300 |
Rock | 0.404852 |
Steel | 0.424529 |
Poison | 0.433262 |
Bug | 0.439006 |
Ice | 0.439604 |
Grass | 0.440364 |
Water | 0.469357 |
Fighting | 0.475616 |
Ghost | 0.484027 |
Normal | 0.535578 |
Ground | 0.541526 |
Psychic | 0.545747 |
Fire | 0.579215 |
Dark | 0.629726 |
Electric | 0.632861 |
Dragon | 0.633587 |
Flying | 0.765061 |
이 정도로 정리가 된다.
특이한 점은 요정 타입이 압도적으로 약하고, 비행속성이 압도적으로 강하다는 점이다.
약한 속성 : 요정, 돌, 강철, 독, 벌레
강한 속성 : 비행, 용, 전기, 악, 불
1def correlation_matrix(df):
2 from matplotlib import cm as cm
3
4 fig = plt.figure()
5 ax1 = fig.add_subplot(111)
6 cmap = cm.get_cmap('jet', 50)
7 cax = ax1.imshow(df.corr(), interpolation="nearest", cmap=cmap)
8 ax1.grid(True)
9 plt.title('relations')
10 labels=['Type 1','HP', 'Attack', 'Defense', 'Sp. Atk', 'Sp. Def', 'Speed', 'Win %']
11 ax1.set_xticklabels(labels,fontsize=7)
12 ax1.set_yticklabels(labels,fontsize=7)
13 fig.colorbar(cax, ticks=[0.00,.05,.10,.15,.20,.25,.30,.35,.40,.45,.50,.55,.60,.65,.70,.75,.8,.85,.90,.95,1])
14 plt.show()
15
16correlation_matrix(mergedResult.loc[:,col])
1sns.regplot(x="Speed", y="Win Percentage", data=mergedResult, logistic=True).set_title("Speed : Win Percentage")
2sns.lmplot(x="Speed", y="Win Percentage", data=mergedResult, hue = 'Type 1', logistic=True)
https://namu.wiki/w/로켓단 문서에 따르면 로켓단이 사용한 포켓몬 개체와 그 수가 작성되어 있다.
7.1. 레드/그린/블루
꼬렛 11마리, 레트라 15마리 - 노말타입, 악타입
주뱃 26마리, 골뱃 7마리 - 독타입, 비행타입
아보 11마리, 아보크 3마리 -독타입
또가스 10마리, 또도가스 1마리 - 독타입, 페어리타입
슬리프 9마리, 슬리퍼 3마리 - 에스퍼타입
알통몬 7마리, 근육몬 2마리 -격투타입
모래두지 4마리, 고지 2마리 - 땅타입 탕구리 5마리, 텅구리 1마리 - 땅타입
승률이 5할이 안되는 타입은 bold처리 하였다. 여기서 알 수 있듯 상위권 타입에 해당하는 용타입, 전기타입, 불타입은 전혀 활용하지 않는 모습을 보여준다.
앞선 분석결과를 바탕으로 컨설팅을 진행하겠다.
앞선 데이터에 따르면, 전기 타입 의 승률은 약 63%이다. 피카츄의 개체값은 둘째치고 어쩌면 매번 당하고 있는 이 장면은 철저하게 고증된 장면이 아닐까.