見出し画像

新企画『子供と1分間プログラミング』ー 初めての データサイエンス:「日本のプロスポーツ選手は4月生まれが多い」って本当?

子供にどうやってプログラミングを教えたらよいか悩んでいる方は多いと思います。国語や算数なら自分の知識で何とでもなりますが、「プログラミング」なんて自分ですらまともにできないものをどうやって教えるか。確かに難題です。

拙著、『今すぐ書ける 1分間プログラミング』は、極簡単なコーディングでパソコンにしゃべらせたり、自分がしゃべったことを理解させたりする音声機能を使うことができ、それを利用して面白いアプリの開発作業を体験する本です。

もちろんこの本に沿って簡単なプログラミング作業を子供と一緒にやってみるのも面白いのですが、全くプログラミングを知らない子供にいきなりコーディング作業をさせるというのもそう簡単なことではありません。

そこで、コーディング作業をちょっとずつ進める1分間プログラミング形式に沿って、子供にプログラミングの第一歩を踏んでもらうプロジェクトをいくつか考えました。『今すぐ書ける 1分間プログラミング』で説明した超初歩的なプログラミング知識で十分対応できるものばかりです。夏休みや休日を利用して子供にちょっとしたコーディング体験をさせたいと思っているお父さん、お母さんには最適な”学習ネタ”だと思いますので、是非取り組んでみてください。

第1弾:1分間プログラミングでデータサイエンス

このプロジェクトは小学校高学年以上の子を想定しています。「日本のプロスポーツ選手に4月、5月生まれが多く、2月、3月は逆に少ない」ということをプログラミングを使って調べてみます。

具体的な作業の流れはこんな感じです。

MagicWandを使ってWikipediaからプロスポーツ選手(サッカー、野球、バスケなど)の一覧データを取得する
❷ 1000人ほどのデータをスキャンして生年月日を抽出する
❸ 月別の人数を表示させて大きな違いがあるかを確認する
❹ 他のスポーツでも同じことが言えるか確かめる

ゲームみたいにすぐ食いつくようなテーマではありませんが、子供が何かのスポーツが好きだったらきっと興味を持ってくれると思います。ただ、あくまでプログラミングが何をするものなのかを体感してもらうのが目的なので、「誕生日に差がある」という話を面白く披露するときっとどの子も興味を持ってくれると思います。

一つ注意点は、できるだけ子供に作業を手伝ってもらうということです。必要なスキルは ① パソコンでタイプ入力ができる、② ネットで簡単な検索ができるという2点だけです。この作業を子供にやってもらわないと単なるデモになってしまうので気を付けてください。

では具体的な会話の例を示しながら、どうやって作業を進めていくか解説していきます。もちろんここに出てくる「たく君」は仮想の男の子で、サッカーが大好きです。ここではお母さんがたく君と一緒にプログラミングをやるというシナリオで話を進めていきます。

ステップ1:たく君、知ってた?

お母さん:ねぇ、たく君の誕生日は8月だよね。でさ、学校の友達の誕生日を全部調べたとするよね。そうしたら3月生まれが多いとか、10月生まれは少ないとか、月によって多かったり少なかったりするのってあると思う?
たく君:えー、1月誕生日の奴ってあまり知らないけど、みんな同じじゃない?
お母さん:そうだよね。別に何月に生まれる子が多いとかないよね。でもさ、日本のプロサッカー選手をみると4月生まれがメチャ多いって知ってた?
たく君:そうなの?あっ、岡崎選手もそういえば4月だな。でもどうして4月が多いの?
お母さん:じゃあ、それが本当かどうかプログラミングで調べてみようか?

まずは問題を提起してみてください

「日本のプロスポーツ選手は4月生まれが多い説」に興味をもってもらわないと、なぜプログラミングをやっているのかわからなくなります。ここは是非とも工夫して、この問題に食いついてくるように仕向けるのが大切です。

後に詳しく解説しますが、サッカー選手だけではなく、他のスポーツのデータを使うこともできますので、もし別のスポーツにすごく興味がある場合はそちらをネタにしたほうがよいでしょう。

ステップ2:どこで選手の情報をゲットするのか教える

お母さん:じゃあね、ブラウザを開けて、Wikipediaに行ってみるよja.wikipedia.orgって入れてみて。
たく君:出たよ。
お母さん:じゃ右上の検索のところで「日本のサッカー選手一覧」って入れてみて。
たく君:出たよ。

このウィキペディアの記事には日本のプロサッカー選手がすべて掲載されています。

サッカー好きの子であればすでに知っているかもしれませんが、まずはここでサッカー選手の膨大なデータはここから見ることができるということをはっきりと確認します。

ステップ3:誕生日はここでわかるよ

お母さん:あいうえお順になっているよね。この最初の「阿井達也」って人のところをクリックしてみて。
たく君:この人知らないけど、出てきたよ。
お母さん:右の方に生年月日があるよね。この人は4月17日だね。
たく君:確かに4月生まれだ!
お母さん:でもみんな調べてみないとね。全部クリックして誕生日メモしてみる?
たく君:えっ?これ全部調べるの?
お母さん:大変だよねぇ~。

画像1

選手の名前がすべてリンクになっていて、それぞれの選手の記事に飛ぶことができます。各ページには決まって右側に選手のデータが一覧になっていて、生年月日はそこに入っています。

ここで是非子供に提案してほしいのは「手作業」です。もちろん子供は困惑するでしょう。サッカー選手一覧は4000人以上もあり、それを一個一個確認することを想像するだけでうんざりします。仮に不思議な子がいて「じゃあやってみよう!」みたいなノリになってもきちんと説明してあげてください。手作業は大変だと…。ここにプログラミングの価値とパワーがあるわけですから。

ステップ4:選手一覧をプログラミングで取得してみる

お母さん:じゃあね、お母さんが書いたプログラミングで、あの選手全員の名前をドバーっとゲットしてみるよ。
たく君:どういうこと?
お母さん:まあ見ていて。ここの「開始」っていうボタンを押してプログラミングを走らせてみるよ。ほら。
たく君:おおっ、すげー。全員入っているの?
お母さん:そうだよ!

ここで初めて「プログラミング」というものを子供にみせます。何がどうなっているのかまだはっきりわからなくても、画面にズラーっと選手名が表示されているのを見て、機械がデータを取得しているイメージが湧くはずです。ここでまずコンソールアプリの出力を見せるのはそこに狙いがあるからです。

事前準備❶:Wikipedia五十音リスト取得アプリ

ではこの選手一覧をゲットするコードを準備します。繰り返しになりますが、Visual Studio 2019の使い方や基本は『今すぐ書ける 1分間プログラミング』を参照してください。

【コンソールアプリを新規作成する】

まず、Nugetパッケージは、WindowsもMacも両方MagicWandCoreを使ってください。『今すぐ書ける 1分間プログラミング』ではWindowsユーザーにはMagicWandWinを用意しましたが、ここでの拡張はMagicWnadCoreのみに収容されています。ですので、Windowsユーザーの方は、コンソールアプリのプロジェクトを新規作成する際には必ず「コンソールアプリ(.Net Core)」を選んでください(本で説明した.Net Frameworkを選択するとエラーが出ます)。Macユーザーの方はいつもと同じ方法でコンソールアプリを作ります。

また、NugetパッケージのMagicWandCoreのバージョンは必ず3.1.0以上のものを使ってください。古いバージョンには追加したメソッドが入っていませんのでご注意を。

【最初のコード】

では新規コンソールアプリのプロジェクトにPlayerListなどと名前を付けてみてください。そして、Mainブロック内に次の5行を書いてください。MagicWandの参照作業も忘れずに。

using MagicWand;
using System;
using System.Collections.Generic;
using System.Text;

namespace DataScienceKids
{
   class Program
   {
       static void Main(string[] args)
       {
           //Wikipediaの記事タイトル
           string title = "日本のサッカー選手一覧";
           //五十音リストをすべて取得
           List<string> players = Magic.GetWikiGojyuonList(title);
           //選手をリストする
           foreach (var player in players)
           {
               Console.WriteLine(player);
           }

           Console.ReadKey();
       }
   }
}

キモとなるのがこのGetWikiGojyuonというメソッドです。

//五十音リストをすべて取得
List<string> players = Magic.GetWikiGojyuonList(title);

これは日本語のWikipediaでモノの一覧が五十音で表示されているページがあれば、そこからすべてのアイテムを抽出するメソッドです。Wikipediaでは「〇〇の一覧」というタイトルで様々なデータが掲載されています。ほぼどれも似たような形式でテキストが組まれているので、一部を除いてリストデータを簡単に抽出できます。

ちなみにスポーツ別選手の一覧記事はここで見ることができます。

これを使ってサッカー選手一覧をゲットします。このアプリでは取得した全選手をコンソールに出力するので、4000人もの選手がズラーっと出てきます。マシンにもよりますが30秒程度はかかりますので、しばらく眺めていてください。

画像2

このズラーっと出てくるとことを子供が見ると、いかにも機械が処理しているという感じが伝わるはずです。繰り返しますがここが重要な狙いですので、このステップは必ずやってみてください。

このステップが終わったら、まずはこのPlayerListプロジェクトを保存しておきます。

ステップ5:生年月日を抽出する

お母さん:これ全部で4千人以上も選手のデータが入っているんだよ。
たく君:4千人もいるの?すごいね。
お母さん:古い人も入れてだからね。でさ、この人たちの誕生日を調べてみようか。
たく君:誕生日はどこにあるの?さっき見たの名前だけだったよ。
お母さん:じゃあさ、一人ひとりの誕生日もプログラミングでもってくるようにしてみるよ。

事前準備❷:各選手の記事から生年月日を取得する

一覧記事から取得した選手名はそのまま記事のタイトルになっているので、それぞれをもとに選手の記事をゲットすることができます。このためにMagicWandにはGetWikipediaという記事内容を取得するメソッドを利用します。

そこで新規プロジェクトを作り、今度はPlayerBirthdayという名前を付け、Mainブロックが入ったProgramm.csは、前のPlayerListからすべてコピペしてきてください。

その上で、foreachブロック内に次の5行を入れてみてください。冒頭のusingにもSystem.Text.RegularExpressionという項目が入っているので注意してください。

using MagicWand;
using System;
using System.Text.RegularExpressions; //新しく追加する
using System.Collections.Generic;
using System.Text;

namespace DataScienceKids
{
   class Program
   {
       static void Main(string[] args)
       {
           //Wikipediaの記事タイトル
           string title = "日本のサッカー選手一覧";
           //五十音リストをすべて取得
           List<string> players = Magic.GetWikiGojyuonList(title);
                       
           //選手をリストする
           foreach (var player in players)
           {
               //選手名だけ取得する
               var items = player.Split(new char[] { '\t' }, StringSplitOptions.RemoveEmptyEntries);
               //選手名で記事を取得する
               var article = Magic.GetWikipedia(items[1]);
               //記事から生年月日を取得
               Match bday = Regex.Match(article, @"生年月日.+?(\d\d\d\d)\|(\d+)\|(\d+)", RegexOptions.Singleline);

               Console.WriteLine(bday);

               if (items[0] == "い") break;
           }

           Console.ReadKey();
       }
   }
}

ここで追加した行を詳細に解説します。

まず最初のSplitのところですが、GetWikiGojyuonメソッドが保存する選手一覧の各項目は、

[五十音の文字] + タブ + 選手の文字列

という形式になっています。

「あ    阿井達也」というテキストでWikipediaを探してもマッチする記事が出てきません。そこでタブの後の選手名だけを取り出したいわけです。そこでSplitという文字列のメソッドを使うと、タブなどの文字列で区切ることができます。

//選手名だけ取得する
var items = player.Split(new char[] { '\t' }, StringSplitOptions.RemoveEmptyEntries);

これを使うと、「あ    阿井達也」という文字列は、最初のitems[0]には「あ」が、次のitems[1]には「阿井達也」が入ります。タブやカンマ、ダッシュ、コロンなど特殊記号で区切られた文字列はすべてこれで分解することができます。

選手名が取得できたらそれをWikipediaで検索します。これはGetWikipediaメソッドを使います。

//選手名で記事を取得する
var article = Magic.GetWikipedia(items[1]);

記事の内容が取得できたら、そこから生年月日のところだけを抽出します。これは正規表現というテクニックを使って行います。

   //記事から生年月日を取得
   atch bday = Regex.Match(article, @"生年月日.+?(\d\d\d\d)\|(\d+)\|(\d+)", RegexOptions.Singleline);       
      

これでどうして生年月日がゲットできるかは正規表現の詳しい解説が必要です。ここでは省きますが、Webスクレイピングと正規表現の詳細な解説は次のマガジン記事で取り上げていますので、ぜひ参考にしてみて下さい。

あとはこのbdayというマッチ項目そのものをConsoleに表示させています。

ただし、ループの最後に次の行が入っています。

if (items[0] == "い") break;

これは、4000以上もの記事を全部開いていくのはあまりに時間がかかり、サーバーにも負担がかかるので、まずは「あ」のセクションだけを表示させるためです。コードはitems[0]つまり文字分割で「五十音文字」のところが「い」になったらループを抜け出す(break)ということです。

それではプログラムを実行してみてください。

画像3

今回は記事を一つひとつ開けるので各行の表示に時間がかかっていることに気が付くと思います。こうした表示を見せることで、各選手の生年月日が一網打尽に取得できる様子がビジュアルに理解できると思います。

ステップ6:生まれた月の集計をする

たく君:これすごいね。選手全員の誕生日なんだよね。
お母さん:じゃあね、このプログラミングを使ってみんなの誕生日を見て、それぞれの月に何人いるか数えてみるよ。
たく君:なんでそんなことするの?
お母さん:ほらさっき話したでしょ。サッカー選手って4月生まれが多いんだっていう話。あれが本当かどうか確かめてみるんだよ。
たく君:そうか。

ここからが本番です!

ここでもまた新たなプロジェクトを作って、今度はAggregateBirthday(誕生日の集計)などと名前を付けてください。そしてPlayerBirthdayプロジェクトのコードをまたそのままコピペしてください。

今度は、ループの中で誕生月をそれぞれカウントしていきます。まずはコードをみてください。

using MagicWand;
using System;
using System.Text.RegularExpressions;
using System.Collections.Generic;
using System.Text;

namespace DataScienceKids
{
   class Program
   {
       static void Main(string[] args)
       {
           Console.OutputEncoding = Encoding.UTF8;

           //Wikipediaの記事タイトル
           string title = "日本のサッカー選手一覧";
           //五十音リストをすべて取得
           List<string> players = Magic.GetWikiGojyuonList(title);

           //月の集計をする整数配列を用意
           int[] bmonthcount = new int[13];

           //4人に一人の割合で集計するforループ
           for (int i = 0; i < players.Count; i += 4)
           {
               //選手名だけ取得する
               var items = players[i].Split(new char[] { '\t' }, StringSplitOptions.RemoveEmptyEntries);
               //選手名で記事を取得する
               var article = Magic.GetWikipedia(items[1]);
               //記事から生年月日を取得
               Match bday = Regex.Match(article, @"生年月日.+?(\d\d\d\d)\|(\d+)\|(\d+)", RegexOptions.Singleline);
               
               //マッチの3つ目、Group[2]に月の数字はある。これが入っていたら集計する
               if (!string.IsNullOrEmpty(bday.Groups[2].Value))
               {
                   //月と同じ配列インデックスの数字を1つプラスする
                   bmonthcount[Int32.Parse(bday.Groups[2].Value)]++;
                   //月の数字を表示する
                   Console.WriteLine(bday.Groups[2].Value);
               }
           }

           Console.WriteLine("月の集計:");
           Console.WriteLine(string.Join("\n", bmonthcount));

           Console.ReadLine();
       }
   }
}

まずは、1月から12月までの数字の入れ物を用意します。『今すぐ書ける 1分間プログラミング』でも配列の説明はしましたが、ここでは文字列ではなく数字(整数:Integer)の配列を用意します。

//月の集計をする整数配列を用意
int[] bmonthcount = new int[13];

月ごとのカウントを入れる配列を用意する

配列の数はどうして13個?これは月の数字と配列のインデクスの数字を一致させるためです。配列は0から始まるので1月から12月までの12個の集計をするには一つ余分に13個の配列作っておきます。

配列:0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 (全部で13個)
月:       1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12

これで配列の4番目、int[3]は月というように、数字が一致するようになりました。もちろん0は無視します(0月などないので)。

なぜこうしたかはすぐ後で説明します。

4人ごとに読み込むループを作る

次に、4000人全部のデータを読むのは大変なので、4分の1の1000人ほどに絞ります。ただ、五十音順で上から1000人だと、後半の「矢野」や「渡辺」などがごっそりと抜けることになります。それでも誕生日の分布には影響ないと思いますが、一応全員を対象に1000人を選びたいので、ループで4人ごとに1人だけを選んで誕生日をチェックするようにしました。

 //4人に一人の割合で集計するforループ
 for (int i = 0; i < players.Count; i += 4)

これまでループはforeachを使ってきましたが、特定のデータだけ見る場合にはforループが便利です。この場合は「0から始まって選手の総数(playsers.Count)まで見て、その間、4人ごとにスキップして読み込む」という意味になっています。そしてplayerのリストも、players[i]のようにリストのインデックスで見るように変更しています。

//選手名だけ取得する
var items = players[i].Split(new char[] { '\t' }, StringSplitOptions.RemoveEmptyEntries);

これで4千人余り入ったplayersリストの中から、0番目、4番目、8番目・・・と4人ずつスキップして4000人を見るので、結局ランダムに選んだ1000人の生年月日を見ることになるのです。

月別に人数をカウントする

月別集計のbmonthcountでカウントしていきますが、インデックスと月の数を一致させたことで、 

bmonthcount[Int32.Parse(bday.Groups[2].Value)]++; 

という一行だけでカウントができるのです。

   //マッチの3つ目、Group[2]に月の数字はある。これが入っていたら集計する
   if (!string.IsNullOrEmpty(bday.Groups[2].Value))
   {
       //月と同じ配列インデックスの数字を1つプラスする
       bmonthcount[Int32.Parse(bday.Groups[2].Value)]++;
       //月の数字を表示する
       Console.WriteLine(bday.Groups[2].Value);
   }

bmonthcountはカウンター配列で、例えば誕生月が4月だったらbmonthcount[4]の入れ物の数字が1つ足されます(++というのはその加算の意味です)。こうしないで、「1月だったら・・・」のように条件文でやっていくと12月まで全部書かないといけないのでコードが煩雑になります。配列の用意でちょっと工夫したのはこのためなのです。

最後に集計結果を表示する

 Console.WriteLine("月の集計:");
 Console.WriteLine(string.Join("\n", bmonthcount));

これで集計配列の中身を一気に表示できます。

画像4

ちなみに1000人のデータを見るのでプログラムが終了するまで3分ほどはかかりますので気長に待っていてください。子供と一緒に画面を眺めていてもよいでしょう。コンピューターが何かがんばって仕事をしている雰囲気も味わえます。

ステップ7:本当に4月が多いのか検証

お母さん:ほら、やっと終わったよ。「月の集計」ってあるよね。この下にあるのが各月ごとに誕生日がある人の数を数えた合計。最初の「2」というのはゴミなので無視してね。1月71人、2月は46人、じゃあ4月は?
たく君:137人だ!多いね。
お母さん:じゃグラフにしてみようか。
たく君:グラフ?

実際に数字をみても明らかですが、ここはもう少しビジュアライズしてみます。そのほうがもっと結果にインパクトが出ます。

プログラミングでグラフを書いてもよういのですが、この程度の簡単な数字ならExcelなどを使ったほうが便利です。

Excelなどの表計算アプリを開いて、最後の集計結果をコピペします。最初の数字「2」は配列の0インデックスに入って、本来はここに数字は入らないはずですが、記事データにゴミが入っているためか、誕生月が0月だと読み込んでいる選手が2人いるようです。ここは無視してその次の数字からコピーしてください。

画像5

そして、12個の数値をグラフ化してみます。

画像6

これを見ると一目瞭然ですよね。

お母さん:ほら、こうやってグラフにするとよくわかるでしょう。4月生まれが一番多くて、5月、6月とちょっとずつ少なくなっている。
たく君:2月と3月が本当に少ないね。
お母さん:なんだか4月からどんどん減っていって、3月が一番少ないね。
たく君:でもどうしてなの?

こんな会話が出てくれば本プロジェクトは大成功です。

プログラミングでデータを分析し、その裏にある理由や背景にぜひとも興味をもってもらいたいのです。

お母さん:これは学校と関係があるんじゃないかな。だってクラスの中で4月生まれの子って大きいでしょ。3月生まれの子と比べて1年も違うんだから。だからサッカーも一番先にうまくなるのかも。だから試合にも早く出させてもらえるとか、そういうことがあるのだと思うよ。
たく君:じゃあ2月とか3月生まれって不利ってこと?
お母さん:不利というより、遅生まれの子より早生まれの子のほうがチャンスが多いということなのかもね。でもあの三浦カズは2月生まれ。あんなスーパースターでも2月生まれということは、不利ということではないと思うよ。
たく君:サッカー以外の選手はどうなの?バスケとか。
お母さん:じゃあ調べてみる?

他のスポーツ選手で調べたい時は、次の記事を参考にしてください。

例えばバスケ選手ならこの記事。

日本のプロ野球選手ならここ。

プログラムの冒頭のtitleを変えるだけで同じ分析ができます。ちなみに野球もバスケも4月生まれが圧倒的に多いですね。ただ、スポーツによってはあまり差がないものもあるかもしれません。いろいろと調査していくと面白い結果が見つかるかもしれません。

ステップ8:子供にコードを変更させる

お母さん:じゃあさ、ここに「日本のサッカー選手一覧」ってあるでしょう。これを「日本のプロ野球選手一覧」に変えてみようか。
たく君:やったよ。で、どうするの?
お母さん:じゃあ、ここ「開始」ってボタン押してみて。
たく君:また数字が出てきた。
お母さん:そう、今度は野球選手の誕生月をみているんだよ。結果が出るまでちょっと待ってようか。
たく君:あっ、終わった。やっぱり四月が多そうだね。

ここから先のExcelでグラフを作るところも是非子供にやってもらっってください。

次のステップ

プログラミングというと、小学校でも始まったプログラミング学習で、スクラッチなどを使ってちょっとしたゲームっぽいものを作るといったイメージがあるかもしれません。

今回はデータサイエンス的な使い方でプログラミングに触れるというアプローチで全くスクラッチなどとは異なります。ただ、子供は興味が湧けばある程度複雑なコーディングでも臆せずにやろうとします。今回のようなコーディングの流れがわからなくても、「どこをいじくればどうなるか」というのさえつかむことができればどんどんとコードを書いていきます。大人はそれをサポートしていけばよいだけです。

子供がプログラミングに入っていく上でとても需要なのは、「これをしたいんだけどどうすればよいの?」というように子供自身が問題意識を持つことです。次回はウェブサイトで遊びながら、インターネットの仕組みについて理解できるプロジェクトを考えてみます。

乞うご期待!


この記事が気に入ったらサポートをしてみませんか?