GistでFizzBuzzのコードを公開してみた

こんにちはー。
ブログ見に来てくれてありがとうございます。じゃのめです。

だんだん蒸し暑くなってきましたね。
最近は毎日会社から帰るとシリコンバレーっていう海外ドラマを観ます。(amazon primeでシーズン4まで配信中)

コーダー達の口から惜しみなく放たれる罵り合いは、私のコーディング意欲を掻き立てます。(なぜ)
www.amazon.co.jp

GitHubを使ってみることにした

GitHubでおれも高度なプログラマーに変身しようと思い
前回作りかけだったブラックジャックアプリとかをとりあえずGitHub上のリポジトリにプッシュしてみました。
これだけで結構大変な思いをした。

github.com

ブラックジャックアプリをGitHubにあげてみますと宣言した記事はこちら

sorivid.hatenablog.com

Gistが便利そう

なにやらGitHubではGistとかいうものがあるらしく
gitとか使わず?GitHubだけの機能でソースコード管理でき
かつそのコードを簡単にブログに載せられるようです。いざ。

こりゃブログに載せるコードは全部Gist使おうかな。ってなります。
ちなみにこのコード、FizzBuzzってやつです。今日初めて知って、初めて書きました。

見てくれてありがとうございました。
おわり

C++でブラックジャックアプリを作る

ブラックジャックを実装すれば初心者を脱出できるらしい

 会社や通勤中、プログラミングの勉強を少しずつしていたわけですが、プログラミングを「知って」いても、「使えない」という状況が続いていました。 結局は何か一つ作り上げないと、自信にもならなければ現状の自分の力を知ることもできないのですよね。当たり前なんですけどね。
 じゃあ何つくればいいの?と思っていたら、Qiitaにこんな記事がありました。 ので、途中まで作りました。 プログラミング入門者からの卒業試験は『ブラックジャック』を開発すべし

ブラックジャックC++で途中まで作りました

がっかりしましたか?コンソールアプリです。
f:id:Sorivid:20180428003204p:plain
何か少しできてそうですが、まだこれは途中です。
まずディーラーのスコアまるわかりだし、
ディーラのスコアなのに「あなたのスコア」になってるし
J、Q、Kのスコアが10じゃないし、
さらにAを1とするか10とするかを選べません。

ひとまず上記をクリアすればいったん作れたといえるのではないでしょうか。 まだ見つかるかもだけど頑張ろ。

途中まで作ってみた感想

Qiitaの記事には簡単な答え合わせというかヒントも記載されているのですが、それを見ない状態でカードクラスや山札クラス、プレイヤークラスなど作れていて、 オブジェクト指向(仮)的なことができているなー、一応少しは勉強身になってんなーと感じてうれしいです。 リストや乱数とか、基本的なところを使いこなせるのってコーディングの速さに直結するなーとか、Qiitaに書いてあるよりももっとこういうクラス設計にしたらいいのでは?とか考えられて面白いです。
ぜひ初心者の皆さんはブラックジャック作ってみよう。

最後に

現時点で本記事にコードはのせませんでした。が、今後編集して載せるつもりです。
Githubを使いこなせていないのでもうちょい時間かかりますが、練習がてら使ってからリンクとしてブラックジャックのコードをここに公開しようと思います。
C#で書き直して、Unityでゲームにしてみるのもいいなあ。

League of Legend RiotAPIでデータサイエンスを勉強しよう【その2】

前回の記事で手に入れた、各試合のデータ(68試合分)から、勝敗にはどんな要因が関係しているのかを探ります。

APIで得られたデータをCSV

前回、APIを繰り返し使用することで、ディクショナリのリストとしてデータを取得しました。 これをcsvファイルにして、保存しておきましょう。 ここでは、よくデータ分析に使われているpandasモジュールを使ってcsvファイルとして出力してます。

import pandas as pd

#statsListというリストにLoLの試合データを前回保存しました。
#これをpandasのデータフレーム型に変更します。
stats_df = pd.DataFrame(statsList)

#stats_dfの中でもあまり試合に関係なさそうなカラム(例えばダブルキルの数とか)をdrop()によってそぎ落としています。
df = stats_df.drop(["perk0",
"perk0Var1",
"perk0Var2",
"perk0Var3",
"perk1",
"perk1Var1",
"perk1Var2",
"perk1Var3",
"perk2",
"perk2Var1",
"perk2Var2",
"perk2Var3",
"perk3",
"perk3Var1",
"perk3Var2",
"perk3Var3",
"perk4",
"perk4Var1",
"perk4Var2",
"perk4Var3",
"perk5",
"perk5Var1",
"perk5Var2",
"perk5Var3",
"perkPrimaryStyle",
"perkSubStyle",
"combatPlayerScore",
"doubleKills",
"firstBloodAssist",
"firstBloodKill",
"firstInhibitorAssist",
"firstInhibitorKill",
"firstTowerAssist",
"firstTowerKill",
"inhibitorKills",
"item0",
"item1",
"item2",
"item3",
"item4",
"item5",
"item6",
"killingSprees",
"largestCriticalStrike",
"largestKillingSpree",
"largestMultiKill",
"neutralMinionsKilled",
"neutralMinionsKilledEnemyJungle",
"neutralMinionsKilledTeamJungle",
"objectivePlayerScore",
"participantId",
"pentaKills",
"playerScore0",
"playerScore1",
"playerScore2",
"playerScore3",
"playerScore4",
"playerScore5",
"playerScore6",
"playerScore7",
"playerScore8",
"playerScore9",
"quadraKills",
"timeCCingOthers",
"totalHeal",
"totalPlayerScore",
"totalScoreRank",
"totalTimeCrowdControlDealt",
"totalUnitsHealed",
"tripleKills",
"trueDamageDealt",
"trueDamageDealtToChampions",
"trueDamageTaken",
"turretKills",
"unrealKills",
"wardsKilled",
"sightWardsBoughtInGame"
], axis=1)

#スリムになったデータをCSVファイルとして保存します。
df.to_csv(path_or_buf = 'LoL.csv', index = False)

これで、jupyternotebookを開くたびにAPIを使う必要がなくなりました。

データをpandasで見てみよう

新しくjupyternotebookを開いて、さっき保存したデータを読み込んでみましょう。

import pandas as pd
from pandas import Series, DataFrame
import numpy as np
import matplotlib.pyplot as plt
#seabornは簡単にきれいなグラフを書くためのモジュールです。
import seaborn as sns
%matplotlib inline

#ファイルを読み込み、データフレームを生成します。
lol_df = pd.read_csv('LoL.csv')

#データフレームのwinデータをカウントプロットで見てみます。
sns.countplot('win',data = lol_df)

f:id:Sorivid:20180221223341p:plain
勝敗の数
こんな感じで勝敗のデータが簡単にプロットできます。

データ解析「相関を見てみよう」

勝敗と関係ありそうなデータは、KDAや、与えたダメージ、オブジェクトへのダメージなどでしょうか。これを探るため、相関を見てみましょう。
相関とはデータ間の関連の強さを示す数値です。 相関係数は-1から1までの実数をとります。例えばassistの数と勝敗の相関をとったとき、
1, 相関係数が1に近ければ、assist数の多い試合で勝利していることになります。
2, 相関係数が-1に近ければ、assist数が少ない試合で勝利していることになります。
3, 相関係数の絶対値が0に近ければ、assist数と勝敗には関連性が無いといえます。

#Winを1、Loseを0とするように関数を作ります。
def f(data):
    if data == True:
        return 1
    else:
        return 0

#データフレームのwinに対して上記の関数をapply()して、あらたなnumWinという列を追加します。
lol_df['numWin'] = lol_df['win'].apply(f)

#データフレーム内の全データ間を総当り的に相関係数を求めます。
#corr()とするだけですので簡単です。
corr_df = lol_df.corr()
#corr_dfのwinの列を見てみます。
corr_df.win
assists                           0.330392
champLevel                        0.150457
damageDealtToObjectives           0.570940
damageDealtToTurrets              0.583484
damageSelfMitigated              -0.243319
deaths                           -0.450515
goldEarned                        0.290285
goldSpent                         0.137464
kills                             0.224459
longestTimeSpentLiving            0.203687
magicDamageDealt                  0.102760
magicDamageDealtToChampions       0.130534
magicalDamageTaken               -0.278148
physicalDamageDealt               0.083411
physicalDamageDealtToChampions    0.018560
physicalDamageTaken              -0.174446
totalDamageDealt                  0.091768
totalDamageDealtToChampions       0.041253
totalDamageTaken                 -0.297823
totalMinionsKilled                0.074603
visionScore                       0.187652
visionWardsBoughtInGame           0.082334
wardsPlaced                       0.115123
win                               1.000000
numWin                            1.000000

勝敗と、その他データとの相関係数を見ることができました。
例えば、deathsとの相関は-0.450515ですから、physicalDamageTakenの-0.174446よりも、-1に近いです。これは、後者に比べてdeathsの少ない試合の方が勝敗に影響しているということです。
winとwinとの相関係数が1なのはあたりまえです。同じ数値なのですから。numWinも同様。

正直相関高いデータがない!

しいていうなら0.5くらいあるdamageDealtToObjectivesとdamageDealtToTurrets 、-0.5くらいのdeathsが有効なデータなのでしょうか。

ヒートマップでもうちょいみやすくしてみましょう。まぁ、この場合あまり見やすくはないんですが。

sns.heatmap(corr_df)

f:id:Sorivid:20180221223346p:plain
ヒートマップ
右端もしくは下端のデータがwinとそれぞれのデータとの相関係数です。1に近いほど赤く、-1に近いほど青く、0に近いほど白い。

マップの左上当たりに目を向けると、goldSpentとgoldEarnedとの相関は、色が濃くなっていますね。 似たような数値ですし当たり前ですね。

そのほかにchampLevelとgoldSpentの相関なんかも高いですね。これもイメージがわきますね。

このデータから何がわかるのか

さて、ではこのデータから何がわかるか。
相関係数から判断すると、オブジェクトにダメージをあたえることを優先してkillされなければ、勝率はあがる!しかしそういうわけではない!!

これはあくまで相関で、killされてない試合が勝率高いのかもしれませんが、killされてないから勝ててるとは言えません。勝ててるからkillされないのかもしれません。相関は因果関係ではありません。
オブジェクトダメージだって、そりゃ勝った試合はネクサスまで壊してるんだから、負けた試合に比べてダメージ量多いのは当たり前ですよね。

正直何もわかりませんでした。

結局これといって結論を出せませんでした。なるべくdeathを抑えるべきだということは何となくわかりましたが、あたりまえですよねそんなの。

lolがオブジェクトを奪うゲームだという裏付けには少し加担できているかもしれません。相手をkillするゲームではないってうまいプレイヤーさんは言いますよね。

今後どう進めていくか

さて、難しいですね。勝利の仕組みを解き明かす方法はないのでしょうか。 てか、ワードが全く相関ないのはびっくり。ある程度の数置かないと勝敗にかかわってこないのかな。それとも毎回同じくらいのワードしか置けてないってことなのかな。

改善点としては、
1, CSを見てないこと。
2, もっと時系列データに注目すること

こんくらいしか今思いついてません。 こんなデータに注目してみたら?とかあったらぜひコメントください。

読んでいただき、ありがとうございました。

データサイエンスをLeague of Legendで勉強しよう

 前回までの記事でなんとなくRiotAPIで得られるデータがどんなものか分かってきたので、 このデータをいじりながらデータサイエンスに入門してみます。

はじめに

 本記事ではRiotAPIで得られた各対戦データをみて、勝った試合と負けた試合でどこか違いがないかを探ります。

コード

APIでデータをとってくる方法については、前回の記事sorivid.hatenablog.comを参照してください。

#前回に加え、以下のモジュールをインポートします。
from time import sleep

#ゲームのマッチリスト情報(自分のロールや、何のチャンプ使ったかとか。100戦分がリストになってます。)を手に入れてみます。
#DoAPIは、APIを使って得られるデータを返す関数です。前回までの記事を参照してください。
#accountIDも、API_KEYも前回までの記事を参照してください。
HundredMatchList = DoAPI(uri + "/lol/match/v3/matchlists/by-account/{0}?api_key={1}".format(accountID, API_KEY) )

# アッシュを使った試合のgameIDをリストにする。(アッシュで試合した数が半分以上のため。)
gameIds = []
for match in HundredMatchList['matches']:
    if match['champion'] == 22: # アッシュのchampionIdは22
        gameIds.append(match['gameId'])

 これで、対象となる対戦のマッチIDをリストにすることができました。 APIを使って、このマッチID一つずつに対して詳細データ(stats)を受け取ります。 その詳細データをまたまたリストにします。

statsList = []
for ID in gameIds:
    OneMatch = DoAPI(uri+'/lol/match/v3/matches/{0}?api_key={1}'.format(ID,API_KEY) )
    for i in range(10):
        if OneMatch['participants'][i]['championId'] == 22:
            statsList.append(OneMatch['participants'][i]['stats'])
    sleep(0.5) # 各APIには、一定時間にリクエストできる回数が決まっているので、sleepを入れてる。

 statsListには、(今回の場合)68戦分のデータが詰まっています。それぞれに勝敗、visionScore、ワードを置いた数など様々な統計データが記録されています(たぶん試合後に見れる戦績に載っている項目)。
 データが準備できたところで、グラフを見てキル数が勝敗と関係しているか確認してみます。

win_element = []
lose_element = []
for i in range(len(statsList)):
    if statsList[i]['win'] == True:
        win_element.append(statsList[i]['kills'])
    else:
        lose_element.append(statsList[i]['kills'])

#ヒストグラムで描画します。
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
ax.hist(win_element, normed = True , alpha = 0.5, label = 'win', bins = 10)
ax.hist(lose_element, normed = True, alpha = 0.5, label = 'lose', bins = 10)
ax.legend()
ax.set_title('The Amount of Kill')

結果

f:id:Sorivid:20180128224952p:plain
チャンピオンを倒した数
 勝った試合の方が負けた方より、キル数のヒストグラムの中心が右寄りですね。 勝った試合ではキル数が多い傾向にあるといえます。
 では、totalDamageDealtToChampionsというデータではどうでしょうか?多分トータルでチャンピオンに与えたダメージですね。 チャンピオンにダメージ与えてるほど勝率は上がりそうなものですがどうでしょうか。。。

f:id:Sorivid:20180128225001p:plain
チャンピオンに与えたダメージ
 なんかあまりヒストグラムの中心に差はないように見えますね。ダメージ与えてた方が勝てそうなものですが、あまり関係ないようです。

 こんな感じで自分の勝ち負けはどこに起因しているのかを、データサイエンスを勉強しながらこのブログでさらせていけたらいいなと思っています。

pythonでLeague of Legendsの統計データを表示してみる【その2】


チームごとのゴールドの変遷を見る

前回に引き続き、今度はゴールドの時系列データを表示してみます。 今回表示するものは、OPGG内でTeamAnalysisから見れるデータです。スクショしてきました。 f:id:Sorivid:20180121193344p:plain

流れ

ほとんど前回と変わりません。

  1. 自身のサモナーネームを使いユーザ情報を取得
  2. 100戦分のリストを取得して、データを表示したい対戦のID(マッチID)を取得
  3. 対戦のタイムラインを取得し、各チームのゴールド変遷をグラフ化

ユーザ情報の取得

 Riotの開発者ページAPI_KEYを取得します。
 APIを使うというとなんか難しそうですが、ただWeb上にあるデータをURLを使って保存するだけです。(たぶん)
 RiotのAPIではJSONデータを使用しているので、jsonモジュールを使い、Pythonの組み込み型であるディクショナリ型に変換します。これでデータの操作が簡単になりました。

from urllib import request
import matplotlib.pyplot as plt
import json
%matplotlib inline

#APIKEYと、APIのURL共通部分の準備
API_KEY = '????-??????-????-????-????-????'
name = "じぶんのなまえ"
region = "jp1"
uri = "https://{0}.api.riotgames.com".format(region) 

#APIを指定するとreadして辞書型で返してくれる関数
def DoAPI(API_URI):
    return json.loads(request.urlopen(API_URI).read()) #requestモジュールでファイル風オブジェクトとやらを返し、それをjsonモジュールで辞書型として返してあげる。

#ユーザ情報を取得
UserInfo = DoAPI(uri + "/lol/summoner/v3/summoners/by-name/{0}?api_key={1}".format(name, API_KEY))

 これでユーザ情報を取得できました。ユーザ情報から得られるアカウントIDは、ほかのAPIを使用するために必要になってくるので、保存しておきます。

マッチIDの取得

 次はデータを表示したい対戦のマッチIDを取得します。

#ゲームのマッチリスト情報(100戦分のリスト)を手に入れる。
accountID = UserInfo['accountId'] #自分のユーザー情報からアカウントIDを手に入れる。
HundredMatchList = DoAPI(uri + "/lol/match/v3/matchlists/by-account/{0}?api_key={1}".format(accountID, API_KEY) )

#マッチIDを取得する
TargetGameId = HundredMatchList['matches'][0]['gameId']

 関心のある対戦が100戦分リストのうちの何戦目かを指定しますが、上記ではHunderedMatchList['matches'][0]['gameId']となっており、0戦目のマッチIDを取得しています。(インデックスは0~99)

ゴールド変遷をグラフ化

#対戦のタイムラインを取得
MatchTimeLine = DoAPI(uri + '/lol/match/v3/timelines/by-match/{0}?api_key={1}'.format(TargetGameId,API_KEY) )

#ゴールドの変遷をリストのリスト[f:id:Sorivid:20180121201402p:plain]で返す
def getTotalGoldTimeLine(TimeLine):
    TotalGoldList = [[],[]]
    for i in range(len(TimeLine['frames'])):
        OneTotalGold = 0
        for key in TimeLine['frames'][i]['participantFrames']:
            if int(key) < 6:
                OneTotalGold += TimeLine['frames'][i]['participantFrames'][key]['totalGold']
        TotalGoldList[0] += [OneTotalGold]
        OneTotalGold = 0
        for key in TimeLine['frames'][i]['participantFrames']:
            if int(key) >5:
                OneTotalGold += TimeLine['frames'][i]['participantFrames'][key]['totalGold']
        TotalGoldList[1] += [OneTotalGold]
    return TotalGoldList
            
GoldTimeLine = getTotalGoldTimeLine(MatchTimeLine)

#ゴールドの変遷をプロット
plt.plot(GoldTimeLine[0])
plt.plot(GoldTimeLine[1])

f:id:Sorivid:20180121201402p:plain
OPGGからスクショした画像と全く同じゴールドの変遷が見れますね。

 また、OPGGでゴールドの変遷をみると1分単位でしかデータの変遷を追えないのですが、今回実際にデータを見てそもそもAPIで取得できるデータが1分間隔なのだということを知りました。

 次はデータ分析的なことができたらいいなと思います。

pythonでLeague of Legendsの統計データを見る【入門】

 データサイエンスに興味を持っています。
 そこで、身近なデータとしてLeagueOfLegendsというゲームの戦績を手に入れてみようと思ったわけです。
 このゲームの開発元のRiotGamesさんの開発者ページ(Riot Developer Portal)にてAPIを提供していますので、チャレンジしてみます。

 言語はpythonでやってみます。

概要:

  1. デベロッパー各々に与えられるAPIキーを開発者ページからコピーして、APIのURL末尾に「?api_key=~~~~~」とする必要があります。
  2. ユーザ情報を取得しアカウントID(数字)を取得
  3. アカウントIDから100戦分のリストを取得し、どれか1戦分のマッチIDを取得
  4. マッチIDからそのマッチの詳細を取得
  5. マッチ詳細にはそのマッチに参加した10人分のデータが入ってるので、自分のだけを抽出
  6. 今回はキル、デス、アシストのデータを円グラフにしてみました。
それでは、上記1~4まで

from urllib import request
import matplotlib.pyplot as plt
import json
%matplotlib inline

#APIKEYと、APIのURL共通部分の準備
API_KEY = 'XXXX-XXXX-XXXX-XXXX-XXXX-XXXXXXXX' #APIキーはRiotのホームページでゲットしてください
name = "Sorivid"
region = "jp"
uri = "https://{0}1.api.riotgames.com".format(region) #URLの共通部分

#ユーザー情報を取得(JSON文字列からディクショナリ型へ)
uri_userInfo = "/lol/summoner/v3/summoners/by-name/{0}?api_key={1}".format(name, API_KEY)
UserInfo = uri + uri_userInfo
Filish_obj_userInfo = request.urlopen(UserInfo).read() 
dic_userInfo = json.loads(file) 

#マッチリスト情報(ロールや、何のチャンプ使ったかとか。)
accountID = dic_userInfo['accountId']
uri_matchList = uri + "/lol/match/v3/matchlists/by-account/{0}?api_key={1}".format(accountID, API_KEY) 
file_matchList = request.urlopen(uri_matchList).read()
file_matchList_py = json.loads(file_matchList)

#とりあえずひとつ、マッチの詳細を手に入れます
uri_match = uri + "/lol/match/v3/matches/{0}?api_key={1}".format(file_matchList_py['matches'][1]['gameId'], API_KEY)
file_match = request.urlopen(uri_match).read()
file_match_py = json.loads(file_match)

次は、上記5まで。
手に入れたマッチの情報から、自分のparticipantIdを見つけます。
マッチの情報では、そのゲームに参加した敵味方合わせて10人にparticipantIdが1~10まで割り当てられています。

#participantIdを見つける。
for x in range(10):
    num = file_match_py['participantIdentities'][x]['player']['accountId'] == dic_userInfo['accountId']
    if num is True:
        participantId = x+1 
print(participantId)

#手に入れたマッチの情報から自分の詳細データを手に入れる。
for x in range(10):
    num = file_match_py['participants'][x]['participantId'] == participantId
    if num is True:
        match_Data = file_match_py['participants'][x]

最後に、上記6。
matplotlibを使って、キルデスアシストを円グラフにしてみます。

plt.pie([match_Data['stats']['kills'], match_Data['stats']['assists'], match_Data['stats']['deaths']], colors = ('Green', 'Orange', 'Red'))

f:id:Sorivid:20171224224304p:plain

 このデータが、マッチ後の詳細データとしてビジュアライズされているんですね。すごい。

 次は、戦績データベースサービス(下記参照)で見ることのできるGold変遷とかチャートにしてみたいな。
jp.op.gg


 pythonとかいろいろ初心者で、コード面の未熟な部分がずいぶんあるとおもいますが、そこも含めてコメント待ってます。
 初投稿でした。