[PYTHON] I analyzed the rank battle data of Pokemon sword shield and visualized it on Tableau

Too Long, Didn’t Read

Hi, have you ever played Pokemon, or Pokemon for short (Pokemon is a registered trademark of Nintendo Creatures Game Freak)?

The second expansion patch of the latest Pokemon Sword Shield (commonly known as the Sword Shield), the crown snowfield, began distribution on October 23, last week, and many Pokemon trainers have returned to the Galar region during this period. is not it.

As usual, I am one of them, and my beloved Pokemon Electivire (black and yellow messed up cool guy) When I heard that I could use it, I felt like I had just started the game while standing upside down.

Aside from the aside, this work sword shield has a function called rank match that allows online interpersonal battles (the ranking is determined by the battle record because it is just a rank), and it is the end content that is the element of this work. One month is one season, and the rank is reset and the Pokemon that can be used are changed at the turn of the season, and the environment changes greatly every season, which is a big difference from the rating match of the past work.

As I mentioned earlier, I haven't touched Pokemon for a long time since I settled on the island of armor (the first expansion patch), so the trend and so-called "[meta] in the rank match of Pokemon sword shields where the environment changes rapidly. ](Https://ja.wikipedia.org/wiki/%E3%83%A1%E3%82%BF) ”is not known, so it is difficult to formulate a strategy.

Of course, as you know, after the distribution of Pokemon HOME in February this year, battle-related data will be disclosed on the smartphone version of the app. It is now possible to collect information such as the top 10 recruitment rates and what kind of techniques you remember.

However, I felt that it was not enough. Is it possible to make something that is more comprehensive and reflects "Tier" more? Such awareness of the problem is the main motivation for starting this article.

Goal

The finished product (spoilers)

Tableau Public

gif2.gif

Goal setting

The starting point this time is

--There is little information that can be obtained from the battle data on Pokemon HOME, I want more —— Data is hard to see and it takes time to get to the data you want

was.

So the landing point is

--Collect data that cannot be obtained only on Pokemon HOME --Visualize data for easy viewing

It seems to be.

Problem solution

However, in order to "capture the trends and meta of each season", which is the goal of this book, it seems that we have to rely on the data of Pokemon HOME, the battle-related data released by Pokemon to the outside is my own. As far as I know, this is all.

If you refer to Pioneer who has acquired the battle data of rank match from API, it seems that you can get the data of Pokemon HOME + α.

This time, I will process the data obtained from this to make it visible so that I can understand something like "Tier" (miscellaneous).

I think there are several visualization methods, but I decided to use Tableau Desktop after comprehensively evaluating the ease of interactive operation, good visuals, and abundant functions (or rather, reflecting my taste). ..

I will present this goal again.

--Processing the data obtained from the API to get more suggestions than the formula gives --Visualize with Tableau to make data easier to see

Let's Try it

1. About API

For the following data download, refer to the article @retrorocket (June 07, 2020). Please read here for details.

curl 'https://api.battle.pokemon-home.com/cbd/competition/rankmatch/list' \
  -H 'accept: application/json, text/javascript, */*; q=0.01' \
  -H 'countrycode: 304' \
  -H 'authorization: Bearer' \
  -H 'langcode: 1' \
  -H 'user-agent: Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Mobile Safari/537.36' \
  -H 'content-type: application/json' \
  -d '{"soft":"Sw"}'

The response obtained from the above API request contains rank match season information.


{
  "code": 200,
  "detail": 0,
  "list": {
    "7": {
      "10072": {
        "name": "Season 7",
        "start": "2020/06/01 13:00",
        "end": "2020/07/01 08:59",
        "cnt": 147244,
        "rule": 1,
        "season": 7,
        "rst": 0,
        "ts1": 1591187503,
        "ts2": 1591187515,
        "reg": "000000248"
      },
      "10071": { //Single battle ID
        "name": "Season 7",
        "start": "2020/06/01 13:00",
        "end": "2020/07/01 08:59",
        "cnt": 147202,
        "rule": 0,
        "season": 7,
        "rst": 0,
        "ts1": 1591187503,
        "ts2": 1591187515,
        "reg": "000000247"
      }
    }, //The following is omitted
}

Enter the season ID and values such as rst here

'https://resource.pokemon-home.com/battledata/ranking/ {season_id} / {rst} / {ts2} / pdetail-{values 1-5}'

You can get data from Pokemon HOME by plunging into and hitting the API.

2. Data download

It's a properly written code, so don't be afraid

(The resources folder and the resources \ split folder are created in advance in the current directory.)

import urllib.request
import json
import datetime
import os

def load_ids():
    ids = "";
    #Load the json obtained from the previous API request
    with open(ID_FILEPATH, 'r', encoding='utf-8') as json_open:
        return json.load(json_open)

def check_dir(path):
    if not os.path.isdir(path):
        os.makedirs(path)

def get_response(url, file_name):
    try:
        with urllib.request.urlopen(url) as response:
            body = json.loads(response.read())
            with open(f'resources//split//{file_name}', 'w') as f:
                json.dump(body, f, indent=4)
        return True
    except urllib.error.URLError as e:
        print(e.reason)
        return False

def make_json(ids):
    for season_number in ids['list'].keys():
        for  season_id in ids['list'][season_number].keys():
            rst = ids['list'][season_number][season_id]['rst']
            ts2 = ids['list'][season_number][season_id]['ts2']
            for i in range(1,6,1):
                url = f'https://resource.pokemon-home.com/battledata/ranking/{season_id}/{rst}/{ts2}/pdetail-{i}'
                file_name = f'Season{season_number}_{"Single" if season_id[4]=="1" else "Double"}_{i}.json'
                if get_response(url, file_name):
                    with open('log', 'a') as f:
                        print(f'{datetime.datetime.now()} | Generated: {file_name}', file=f)

def merge_json(ids):
    for i in ids['list'].keys():
        for j in ids['list'][i].keys():
            rule = "Single" if j[4] == '1' else "Double"
            files = []
            for n in range(1,6,1):
                with open(f'.//resources//split//Season{i}_{rule}_{n}.json', 'r', encoding='utf-8') as json_open:
                    files.append(json.load(json_open))
            jsonMerged = {**files[0], **files[1], **files[2], **files[3], **files[4]}
            file_name = f'Season{i}_{rule}_master.json'
            with open(f'resources//{file_name}', 'w') as f:
                json.dump(jsonMerged, f, indent=4)
            with open('log', 'a') as f:
                print(f'{datetime.datetime.now()} | Merged   : {file_name}', file=f)

if __name__ == "__main__":
    ids = load_ids()
    #Please specify your favorite directory here
    for path in ['.//resources', './/resources//split']:
        check_dir(path)
    make_json(ids)
    merge_json(ids)
    print('Suceeded')

Running the above script will save the json file of the battle data from season 1 to the latest season.

However, the trouble is that the json file is divided into 5 parts every season, which is very troublesome.

Let's merge them into one file per season.

def merge_json(ids):
    for i in ids['list'].keys():
        for j in ids['list'][i].keys():
            rule = "Single" if j[4] == '1' else "Double"
            files = []
            for n in range(1,6,1):
                with open(f'.//resources//split//Season{i}_{rule}_{n}.json', 'r', encoding='utf-8') as json_open:
                    files.append(json.load(json_open))
            jsonMerged = {**files[0], **files[1], **files[2], **files[3], **files[4]}
            with open(f'resources//Season{i}_{rule}_merged.json', 'w') as f:
                json.dump(jsonMerged, f, indent=4)


ids = "";
with open(ID_FILEPATH, 'r', encoding='utf-8') as json_open:
    ids = json.load(json_open)

make_jsonchunk(ids)

With this, the large number of json files mentioned earlier will have been aggregated one by one.

The contents of this json are as follows.

//This time pokemon one combined json of the appropriate season.I named it json
// .\Datachunk\pokemon.json
{
    "Picture book number" : {
        "p_detail_id":{
            "temoti":{
                //Top 10 techniques used
                "waza":[
                    {
                        "id":"xxxx",
                        "val":"value"  //Recruitment rate, percentage
                    },
                    ...
                ],
                //Adopted characteristics
                "tokusei":[
                    {
                        "id": "xxxx",
                        "val": "value" //Recruitment rate, percentage
                    },
                    ...
                ],
                //Top 10 Pokemon in your belongings
                "motimono": [
                    {
                        "id": "xxxx",
                        "val": "value" //Recruitment rate, percentage
                    },
                    ...
                ],
                //Top 10 Pokemon that are included in the battle team together
                "pokemon": [
                    {
                        "id": "xxxx",
                        "form": "value" //Form
                    },
                    ....
                ]
            },
            "lose": {
                //Top 10 techniques to defeat this Pokemon
                "waza": [
                    {
                        "id": "xxxx",
                        "val": "value" //percentage
                    },
                    ...
                ],
                //Top 10 Pokemon that defeated this Pokemon
                "pokemon": [
                    {
                        "id": "xxxx",
                        "form": "value" //Form
                    },
                    ...
                ],
            },
            "win": {
                //Top 10 techniques defeated by this Pokemon
                "waza": [
                    {
                        "id": "xxxx",
                        "val": "value" //percentage
                    },
                    ...
                ],
                //Top 10 Pokemon defeated by this Pokemon
                "pokemon": [
                    {
                        "id": "xxxx",
                        "form": "value" //Form
                    },
                    ...
                ]
            }
        }
    }
}

It seems that you can get various information such as techniques adopted for Pokemon outside the TOP 10 and Pokemon adopted together, which can not be obtained at Pokemon HOME.

In summary, the data that can be acquired are as follows

  1. Top 10 techniques used
  2. Adopted characteristics
  3. Top 10 Pokemon in your inventory
  4. Top 10 Pokemon that are included in the battle team together
  5. Top 10 techniques to defeat this Pokemon
  6. Top 10 Pokemon that defeated this Pokemon
  7. Top 10 techniques defeated by this Pokemon
  8. Top 10 Pokemon defeated by this Pokemon

Make full use of these data and try to calculate the most plausible tier.

However, this time, the tier calculation method is not the main subject, so I will consider an index that seems to give a result like that.

3. Tier selection

--Problem: I want Pokemon with a high party recruitment rate and a high selection rate to come to the top. --Issue: Since there is no data on the selection rate and recruitment rate, it is necessary to replace it with some kind of index.

How to calculate meta

Think from the meta

Tier 1, that is, environment top meta Refers to the strongest and most popular Pokemon, so we will create an index centered on "strong" and "fashionable".

"strong"

The data I have this time includes "Top 10 Pokemon that defeated this Pokemon". The number of defeats and the number of opponents that can be defeated are considered to substitute for the strength of the Pokemon in the environment.

"Is fashionable"

The most intuitive indicator of "popular" criteria is party recruitment, but this time the data is not available and should be replaced by other criteria. Since this data includes "Top 10 Pokemon used with this Pokemon", we decided to calculate Pokemon that are considered to be used by a wide range of parties from the ranking data based on this data. .. In addition, the number of elections is considered to increase in proportion to the number of defeats mentioned above, so the party recruitment rate alone is used as an index of whether or not it is "popular".

Trial

Library import

import json
import csv
import pandas as pd
from sklearn import preprocessing

Data read

pokedex = "";
with open('.//Datachunk//bundle.json', 'r', encoding='utf-8') as json_open:
    pokedex = json.load(json_open)

pokedex = "";
with open('.//Datachunk//bundle.json', 'r', encoding='utf-8') as json_open:
    pokedex = json.load(json_open)

pdetail = "";
with open('.//Datachunk//pokemon.json', 'r', encoding='utf-8') as json_open:
    pdetail = json.load(json_open)

File output function

def make_csv(pdetail, filename, method = 'temoti'):
    # method = 'temoti', 'win', 'lose'
    write_csv(["Book Number","Pokemon", "component", "value_or_rank"], filename, "w")
    for pokenum in  list(pdetail.keys()):
        for p_detail_id in list(pdetail[pokenum].keys()):
            t_name = get_pokemonname(pokenum, p_detail_id)
            for rank, poke_associations in enumerate(list(pdetail[pokenum][p_detail_id][method]['pokemon'])):
                a_name = get_pokemonname(poke_associations['id'], poke_associations['form'])
                write_csv([pokenum, t_name, a_name, rank+1] , filename, "a")

Trend index calculation & output function

def make_index(filename):
    df = pd.read_csv(filename, encoding='utf-8')
    concated_df1 = df.groupby('component', as_index=False)['value_or_rank'].mean()
    concated_df1.columns = ['Pokemon', 'RankAverage']

    concated_df2 = df.groupby('component', as_index=False)['value_or_rank'].sum()
    concated_df2.columns = ['Pokemon', 'Top10Count']

    concat_df = pd.concat([concated_df1,concated_df2], axis = 1, join = 'inner')
    concat_df =pd.concat([concated_df1[concated_df1.columns[0]], \
                concat_df.drop(concat_df.columns[2], axis =1)], axis = 1)

    concat_df['RankAverage_std'] = preprocessing.minmax_scale(concat_df['RankAverage'])
    concat_df['Top10Count_std'] = preprocessing.minmax_scale(concat_df['Top10Count'])

    concat_df['Crt'] = concat_df["RankAverage"] * concat_df["Top10Count"]
    concat_df['Crt_by_std'] = concat_df['RankAverage_std'] * concat_df['Top10Count_std']
    return concat_df.sort_values('Crt', ascending = False)

Run

make_csv(pdetail, "test1.csv", 'lose')
make_index('test1.csv').to_csv('test2.csv', index=False)
Pokémon Average recruitment ranking Recruitment ranking TOP10 count RankAverage_std Top10Count_std Crt Crt_by_std
Drews 4.863158 462 0.429240 0.956432 2246.778947
Conkeldurr 5.742424 379 0.526936 0.784232 2176.378788
Dusclops 4.747368 451 0.416374 0.933610 2141.063158
... ... ... ... ... ...

スクリーンショット_2020_10-27_185731.png

* Note: The above is created from double battle data

It seems that the fighting was Loebsin's choice this season.

I feel that it can be reflected roughly.

Calculation of meta index

The meta index is calculated from the normalized [number of enemies that can be defeated] * [rank].

The result was output from the same function as before.

スクリーンショット_2020_10_28_043415.png

The number of Pokemon listed in the ranking was less than the recruitment ranking. It's a little surprising that Laplace was the biggest, but I feel like it's double.

It's a calculation method that is too rough, but I'm trying things out, so I decided to use these two indicators for the time being.

Visualization

Scatter plot

As for how to make the shape on the scatter plot arbitrary, I will write an article again someday because it deviates from the main subject.

Please refer to here for urgent information.

I also borrowed the Pokemon icon here.

スクリーンショット_2020-10-29_205435.png

Clustering

I set the number of clusters to 10 and tried clustering. It seems that I can add a tier (I feel).

スクリーンショット_2020-10-29_205057.png

Season rule Pokémon Average recruitment ranking Recruitment ranking TOP10 count RankAverage_std Top10Count_std Crt Crt_by_std
Season 1 single Drews 4.863158 462 0.429240 0.956432 2246.778947
Season 1 single Conkeldurr 5.742424 379 0.526936 0.784232 2176.378788
Season 1 double Dusclops 4.747368 451 0.416374 0.933610 2141.063158
Season 2 single ... ... ... ... ... ...

Data generation

The previous index is output for both singles and doubles for all seasons. You can do it one by one by hand, but it is troublesome, so prepare a program.

def Rename(x):
    for key in rename_dict.keys():
        if x[2] == key:
            x[2] = rename_dict[key]
    return x[2]

rename_dict = {'Meowstic':'Meowstic♂',
'Gilgard':'Gilgard盾',
'Darmanitan':'DarmanitanN',
'Basculin':'Basculin赤',
'Lugargan':'Lugargan昼',
'Metheno':'Metheno(meteor)',
'Yessan':'Yessan♂'}

As an aside, I'm using this function to rename it because it's a bit tricky to visualize on Tableau. I won't touch it this time, so I hope you can think "I'm not changing the name".

def cal_crt(df, method='temoti'):
    if method == 'temoti':
        row_name = "Epidemic index"
    elif method == 'win':
        row_name = 'Meta index'

    concated_df1 = df.groupby('B', as_index=False)['value'].mean()
    concated_df1.columns = ['Pokemon', 'RankAverage']

    concated_df2 = df.groupby('B', as_index=False)['value'].sum()
    concated_df2.columns = ['Pokemon', 'Top10Count']

    concat_df = pd.concat([concated_df1,concated_df2], axis = 1, join = 'inner')
    concat_df =pd.concat([concated_df1[concated_df1.columns[0]], \
                concat_df.drop(concat_df.columns[2], axis =1)], axis = 1)

    concat_df['RankAverage_std'] = preprocessing.minmax_scale(concat_df['RankAverage'])
    concat_df['Top10Count_std'] = preprocessing.minmax_scale(concat_df['Top10Count'])

    concat_df['Crt'] = concat_df["RankAverage"] * concat_df["Top10Count"]
    concat_df[row_name] = concat_df['RankAverage_std'] * concat_df['Top10Count_std']
    df = concat_df.sort_values('Crt', ascending = False)
    return df.drop(['RankAverage', 'Top10Count', 'RankAverage_std', 'Top10Count_std', 'Crt'], axis=1)
def get_name(num, p_detail_id, method='pokemon'):
    if method == 'pokemon':
        name = ''
        if num == "876":
            if p_detail_id == "0":
                name = "Yessan ♂"
            else:
                name = "Yessan ♀"
        elif num == "479":
            if p_detail_id == "0":
                name = "Rotom (default)"
            elif p_detail_id == "1":
                name = "Rotom (Tue)"
            elif p_detail_id == "2":
                name = "Rotom (Wednesday)"
            elif p_detail_id == "3":
                name = "Rotom (ice)"
            elif p_detail_id == "4":
                name = "Rotom (flying)"
            elif p_detail_id == "5":
                name = "Rotom (grass)"
        else:
            name = pokedex['poke'][int(num) -1]
    elif method == 'motimono':
        name = pokedex['item'][num]
    else:
        name = pokedex[method][num]

    return name
def data_trans(pdetail, method1 = 'temoti', method2='pokemon', column =  ["A", "B", "value"]):
    t_names = []
    a_names = []
    ranks = []
    for pokenum in  list(pdetail.keys()):
        for p_detail_id in list(pdetail[pokenum].keys()):
            t_name = get_name(pokenum, p_detail_id, method='pokemon')
            for rank, component in enumerate(list(pdetail[pokenum][p_detail_id][method1][method2])):
                a_name = get_name(component['id'], component[list(component.keys())[1]], method=method2)
                t_names += [t_name]
                a_names += [a_name]
                ranks += [rank+1]
    return pd.DataFrame(
        data = {column[0]: t_names,column[1]: a_names,  column[2]: ranks},
        columns = column
    )
from pathlib import Path
import os
import re
#Select your own directory
file_dir = ".//resources"
p = Path(file_dir)
files = sorted(p.glob("*"))

Seasons = []
Rules = []
df_master = pd.DataFrame(columns = ['Season', 'Rule', 'Pokemon','Epidemic index', 'Meta index'])
for rule in ['Single', 'Double']:
    for season_num in range(1,12,1):
        for method in ['temoti', 'win']:
            with open(f'{file_dir}//Season{season_num}_{rule}_master.json', 'r', encoding='utf-8') as json_open:
                data = json.load(json_open)
            if method == 'temoti':
                df_fashion = cal_crt(trans_data(data, method=method), method=method)
            elif method == 'win':
                df_meta =  cal_crt(trans_data(data, method=method), method=method)

        df = pd.merge(df_fashion, df_meta, on='Pokemon', how='outer').fillna(0)

        df['Season'] = season_num
        df['Rule'] = rule

        df_master = pd.concat([df_master, df], axis = 0)

df_master['Pokemon']  = df_master.apply(Rename,axis=1)
df_master.to_csv(f'ALL_SEASON_METAVALUES.csv', index=False)

4. Dashboard

I decided to create a dashboard that displays information such as Pokemon that is easy to be adopted when you mouse over the Pokemon on the above scatter plot.

Specifications study

For the time being, I want to display the following data that can be read from raw data.

  1. Top 10 techniques used
  2. Adopted characteristics
  3. Top 10 Pokemon in your inventory
  4. TOP10 Pokemon that are included in the battle team together
  5. Top 10 techniques to defeat this Pokemon
  6. TOP10 Pokemon that defeated this Pokemon
  7. Top 10 techniques defeated by this Pokemon
  8. TOP10 Pokemon defeated by this Pokemon

Data generation

Create csv to make it easier to handle when generating data.

new_dict = {}
for n in pokedex['item'].keys():
    n = int(n)
    if n < 148:
        pass
    elif n < 260:
        id_ = n-143
        new_dict[id_] = pokedex['item'][str(n)]
    elif 264 < n:
        id_ = n-148
        new_dict[id_] = pokedex['item'][str(n)]

pd.DataFrame(new_dict.values(), index=new_dict.keys(), columns = ['item']).to_csv('item_index.csv')

pd.DataFrame(pokedex['waza'].values(), index=pokedex['waza'].keys(), columns = ['waza']).to_csv('skill_index.csv')

pd.DataFrame(pokedex['tokusei'].values(), index=pokedex['tokusei'].keys(), columns = ['tokusei']).to_csv('tokusei_index.csv')

On hand

%%timeit

Seasons = []
Rules = []
column_a = {'waza': 'Techniques with high adoption rate','pokemon':'Pokemon with a high combination rate' , 'tokusei':'Characteristics with high adoption rate' , 'motimono':'What to bring with a high adoption rate'}
file_names = {'waza':'ALL_SEASON_SKILL.csv','pokemon':'ALL_SEASON_COMBIND_PARTNER.csv', 'tokusei':'ALL_SEASON_IDIOSYNCRASY.csv', 'motimono':'ALL_SEASON_ITEM.csv'}
for method in column_a.keys():
    df_master = pd.DataFrame(columns = ['Season', 'Rule', 'Pokemon', column_a[method], f'Rank_{column_a[method]}'])
    for rule in ['Single', 'Double']:
        for season_num in range(1,12,1):
            with open(f'{file_dir}//Season{season_num}_{rule}_master.json', 'r', encoding='utf-8') as json_open:
                data = json.load(json_open)
            df = data_trans(data, method2 = method, column = ['Pokemon', column_a[method], f'Rank_{column_a[method]}'])
            df['Season'] = season_num
            df['Rule'] = rule
            
            df_master = pd.concat([df_master, df], axis = 0)
            
    df_master['Pokemon']  = df_master.apply(Change_Name,axis=1)
    df_master.to_csv(file_names[method], index=False)

53.9 s ± 3.33 s per loop (mean ± std. dev. of 7 runs, 1 loop each)

Defeated technique and defeated Pokemon

First of all, from the technique and Pokemon that defeated this Pokemon.

%%timeit

Seasons = []
Rules = []
column_a = {'waza': 'Defeated technique','pokemon':'Defeated Pokemon'}
file_names = {'waza':'ALL_SEASON_KNOCKED_SKILL.csv','pokemon':'ALL_SEASON_KNOCKED_BY.csv'}
for method in column_a.keys():
    df_master = pd.DataFrame(columns = ['Season', 'Rule', 'Pokemon', column_a[method], f'Rank_{column_a[method]}'])
    for rule in ['Single', 'Double']:
        for season_num in range(1,12,1):
            with open(f'{file_dir}//Season{season_num}_{rule}_master.json', 'r', encoding='utf-8') as json_open:
                data = json.load(json_open)
            df = data_trans(data,method1='lose', method2 = method, column = ['Pokemon', column_a[method], f'Rank_{column_a[method]}'])
            df['Season'] = season_num
            df['Rule'] = rule
            
            df_master = pd.concat([df_master, df], axis = 0)
            
    df_master['Pokemon']  = df_master.apply(Change_Name,axis=1)
    df_master.to_csv(file_names[method], index=False)

17.6 s ± 1.14 s per loop (mean ± std. dev. of 7 runs, 1 loop each)

Defeated techniques and defeated enemies

%%timeit

Seasons = []
Rules = []
column_a = {'waza': 'Defeated technique','pokemon':'Defeated Pokemon'}
file_names = {'waza':'ALL_SEASON_KNOCKING_SKILL.csv','pokemon':'ALL_SEASON_KNOCKING.csv'}
for method in column_a.keys():
    df_master = pd.DataFrame(columns = ['Season', 'Rule', 'Pokemon', column_a[method], f'Rank_{column_a[method]}'])
    for rule in ['Single', 'Double']:
        for season_num in range(1,12,1):
            with open(f'{file_dir}//Season{season_num}_{rule}_master.json', 'r', encoding='utf-8') as json_open:
                data = json.load(json_open)
            df = data_trans(data,method1='win', method2 = method, column = ['Pokemon', column_a[method], f'Rank_{column_a[method]}'])
            df['Season'] = season_num
            df['Rule'] = rule
            
            df_master = pd.concat([df_master, df], axis = 0)
            
    df_master['Pokemon']  = df_master.apply(Change_Name,axis=1)
    df_master.to_csv(file_names[method], index=False)

15.7 s ± 1.14 s per loop (mean ± std. dev. of 7 runs, 1 loop each)

Visualization

Now that we have the eight files that correspond to the list above, let's dive into the Tableau workbook and display them.

Union the 9 csv files created earlier and combine them with the file in which the race value etc. are recorded. The latter file came out abruptly, which is needed to use the custom shape feature to display a Pokemon mini-icon on a scatter plot. I won't touch it deeply this time because it is unnecessary if you just make a scatter plot.

image4

Once the data is read, all you have to do is install it. Tableau has excellent operability and is very good (direct marketing).

I uploaded it on [Tableau Public](https://public.tableau.com/shared/GD57KTRKF ?:display_count=y&:origin=viz_share_link), so if you want to see the finished product, please do.

Please forgive me that the design is almost the default setting.

When you touch the finished product, it looks like this.

gif2.gif

Various action functions have been added to the dashboard. See here for Tableau mouseover actions.

5. Confirmation of goal

--Process the data obtained from the API to get more suggestions than the formula gives --Visualize with Tableau to make your data easier to see

This time, we have succeeded in showing the transition of the time series and the single / double battle environment by defining the indicators of the epidemic index and the meta index as scatter plots.

It can be said that the above two goals have been almost achieved.

On the other hand, the above-mentioned indicators have the following problems.

  1. There is a difference from the official recruitment rate ranking (example: patch ragon rank is low)

  2. There is a difference from the tier table issued by the user (example: patch ragon rank is low)

  3. Pokemon that make invisible contributions are underestimated (If you do not defeat the enemy, the meta index will be low, so the rank of support type Pokemon tends to be low, Pokemon that can bind the election of the opponent just by holding it Is not reflected, etc.)

  4. Clear tier calculation is not possible (this time, non-hierarchical clustering is used, but it is not possible to specify up to tier 〇).

I think there are various other problems such as. As this index will improve in the future, it would have been meaningful to be able to visualize the battle data of ranked battles.

~~ I would like to upload it to github when I feel like it. ~~

→ Uploaded (2020/11/03)

See you again.

Postscript

2020/11/03 Github has released the entire code.

environment

  1. Windows10 Home 1903

  2. Python 3.7.6

  3. Pandas 1.0.1

  4. Sklearn 0.23.2

  5. Tableau Desktop 2020.1.20.0427.1803

Source

-Electivire-Pokédex (Pokémon official) -What is Pokemon HOME?-Pokémon Home Official Site -Meta-Wikipedia -Analyze JSON of Pokemon Home battle data (rank battle). --return $ lock -Visualize the battle data of the rank battle of Pokemon Sword Shield with Metabase. --Qiita -Top Meta-MTGWiki -Limit the display of marks in the view --Tableau

© 2020 Pokémon © 1995-2020 Nintendo / Creatures Inc./GAME FREAK inc. Pokemon, Pokemon, and Pokémon are registered trademarks of Nintendo, Creatures, and Game Freak.

Recommended Posts

I analyzed the rank battle data of Pokemon sword shield and visualized it on Tableau
I vectorized the chord of the song with word2vec and visualized it with t-SNE
I tried to rescue the data of the laptop by booting it on Ubuntu
I tried to rescue the data of the laptop by booting it on Ubuntu
[Python3] Take a screenshot of a web page on the server and crop it further
Maybe I overestimated the impact of ShellShock on CGI
I tried using the API of the salmon data project
I analyzed the rank battle data of Pokemon sword shield and visualized it on Tableau
Fixed-point observation of specific data on the Web by automatically executing the Web browser on the server (Ubuntu16.04) (1) -Web browser installation-
Visualize the center of the rank battle environment from the Pokemon Home API
I took Apple Watch data into Google Colaboratory and analyzed it
[Python] I analyzed the diary of a first-year member of society and made a positive / negative judgment on the life of a member of society.
Upload data to s3 of aws with a command and update it, and delete the used data (on the way)
[Personal memo] Get data on the Web and make it a DataFrame
I tried 200 magical exchanges [Pokemon Sword Shield]
Pokemon x Data Science (3) --Thinking about Pokemon Sword Shield Party Construction from Network Analysis Where is the center of the network?
I read and implemented the Variants of UKR
[Python3] Take a screenshot of a web page on the server and crop it further
[SLAYER] I visualized the lyrics of thrash metal and checked the soul of steel [Word Cloud]
Data Langling PDF on the outbreak of influenza by the Ministry of Health, Labor and Welfare
[Challenger Wanted] The fastest Data Loading and Data Augmentation (Kaggle notebook) I can think of
I just wanted to extract the data of the desired date and time with Django
Read the csv file with jupyter notebook and write the graph on top of it
I tried to make it easy to change the setting of authenticated Proxy on Jupyter
[Pokemon Sword Shield] I tried to visualize the judgment basis of deep learning using the three family classification as an example.
I don't like to be frustrated with the release of Pokemon Go, so I made a script to detect the release and tweet it