【ローカル完結型・ブラウザデータサイエンス教材】
コード枠の「📋 コピー」を押すと1タップでコピーできます。Google Colaboratoryで動作を確認したら、各項目の「完了チェック」を押して学習記録をつけていきましょう。数値回答のお題には自動正誤判定システムが組み込まれています。進捗はすべてブラウザ(LocalStorage)に自動保存されます。
01. 高校生のためのPandas入門 on Google Colaboratory
1. はじめに:PandasとColabって何?
Google Colaboratory (Colab) とは?
Googleが提供している、ブラウザ上でPythonを書いて実行できる無料のWebサービスです。環境設定の苦労がなく、誰でもすぐにデータ分析を始められます。教材のコードをColabのセルに貼り付けて実行していきましょう。
Pandas とは?
Pythonで表形式(Excelのような表データ)を自在に操作するためのデータサイエンス標準ライブラリです。
Pandasのインポート(おまじない)
Colabには最初からPandasが入っています。使うときは短く pd と呼ぶのが世界共通のルールです。
import pandas as pd
2. Pandasの基本:Series(シリーズ)とDataFrame
Pandasには2大データ構造があります。
- Series(シリーズ): 1次元データ(1つの列)。値にインデックス(ラベル名)を付けられます。
- DataFrame(データフレーム): 2次元の表データ。複数の列で構成され、Excelのシートと同じ感覚で扱えます。
import pandas as pd
# 1. Seriesの作成(果物と価格)
fruits = pd.Series([100, 150, 200, 120], index=['りんご', 'バナナ', 'いちご', 'みかん'])
print("--- Series ---")
print(fruits)
# 2. DataFrameの作成(生徒の成績表)
student_data = {
'出席番号': [1, 2, 3, 4],
'名前': ['佐藤', '鈴木', '高橋', '田中'],
'数学': [85, 92, 78, 88],
'英語': [76, 88, 95, 82]
}
df = pd.DataFrame(student_data)
print("\n--- DataFrame ---")
display(df)
3. データの読み込みと書き出し
pd.read_csv() でWeb上のURLやローカルのCSVファイルを直接読み込めます。to_csv('ファイル名.csv', index=False) でファイル書き出しも簡単です。
# Web上のCSVを直接DataFrameに読み込む
csv_url = 'https://raw.githubusercontent.com/pandas-dev/pandas/main/doc/data/titanic.csv'
titanic_df = pd.read_csv(csv_url)
# 先頭5行を表示
display(titanic_df.head())
# 成績データをCSVに出力
df.to_csv('class_scores.csv', index=False)
print("class_scores.csv として保存完了!")
4. まずはデータを観察してみよう
データを手に入れたら、まず全体像をつかむのがデータサイエンティストの第一歩です。
shape: 行数と列数(データの大きさ)info(): 各列のデータ型や欠損値の有無describe(): 数値列の平均値、最小値、最大値などの基本統計量
print("--- shape (行数, 列数) ---")
print(titanic_df.shape)
print("\n--- info() ---")
titanic_df.info()
print("\n--- describe() ---")
display(titanic_df.describe())
5. 欲しいデータを自由に取り出す(選択と抽出)
条件に一致する行だけを抜き出すには角カッコ df[条件式] を使います。複数条件は & (AND) や | (OR) を使い、各条件を小カッコ () で囲みます。
# 1. 18歳未満の乗客
children = titanic_df[titanic_df['Age'] < 18]
print("18歳未満の人数:", len(children))
# 2. 女性(female) かつ 1等客(Pclass=1)
rich_women = titanic_df[(titanic_df['Sex'] == 'female') & (titanic_df['Pclass'] == 1)]
display(rich_women.head())
6. 簡単なデータ加工
新しい列の計算追加や、不要な列の削除(drop(..., axis=1))を試します。
# 新しい列の追加 (1ポンド=150円換算)
titanic_df['Fare_JPY'] = titanic_df['Fare'] * 150
display(titanic_df[['Name', 'Fare', 'Fare_JPY']].head())
# 列の削除
titanic_df_clean = titanic_df.drop('Fare_JPY', axis=1)
display(titanic_df_clean.head())
7. 実践練習:クラスのテスト結果を分析しよう!
【お題】期末テスト結果の合計点・平均点・トップ生徒の算出
import pandas as pd
scores_df = pd.DataFrame({
'名前': ['A君', 'Bさん', 'C君', 'Dさん', 'Eさん'],
'国語': [82, 88, 76, 95, 65],
'数学': [78, 92, 85, 89, 72],
'理科': [85, 91, 78, 98, 68],
'社会': [88, 79, 82, 92, 75],
'英語': [76, 95, 88, 91, 78]
})
# 1. 各生徒の合計点と平均点を追加
subjects = ['国語', '数学', '理科', '社会', '英語']
scores_df['合計点'] = scores_df[subjects].sum(axis=1)
scores_df['平均点'] = scores_df[subjects].mean(axis=1)
display(scores_df)
# 2. 合計点トップの生徒
top_idx = scores_df['合計点'].idxmax()
print("トップ:", scores_df.loc[top_idx]['名前'], f"({scores_df.loc[top_idx]['合計点']}点)")
# 3. 理科90点以上の生徒
display(scores_df[scores_df['理科'] >= 90])
第1章 実践チャレンジお題
scores_df を使って、「数学が85点以上(scores_df['数学'] >= 85)」の生徒の人数を求め、半角数字で回答してください。
💡 ヒントを表示
math_high = scores_df[scores_df['数学'] >= 85]
print("人数:", len(math_high))
scores_df を使って、「英語」列の平均点(mean())を計算し、小数第1位まで(例: 85.6)入力してください。
💡 ヒントを表示
print("英語の平均点:", scores_df['英語'].mean())
scores_df で5科目の合計点を算出し、「学年トップ(最も合計点が高い生徒)の合計点」を求めて数字のみで入力してください。ヒントはありません!これまでの知識を総動員して自力でコードを書いてみましょう。
02. 高校生のためのPlotly入門 on Google Colaboratory
1. はじめに:Plotlyって何?
Plotly(プロットリー)は、カーソルを合わせると数値がポップアップしたり、ズームができる対話型(インタラクティブ)なグラフを瞬時に作れるライブラリです。
import plotly.express as px import pandas as pd
2. 基本のグラフを作ってみよう(Plotly Express)
散布図(scatter)、折れ線(line)、棒グラフ(bar)の基本形です。
# 1. 散布図 fig_scatter = px.scatter(x=[85, 92, 78, 88, 75], y=[76, 88, 95, 82, 80], title="数学と英語の相関") fig_scatter.show() # 2. 折れ線グラフ fig_line = px.line(x=['月', '火', '水', '木', '金', '土', '日'], y=[120, 150, 180, 160, 210, 250, 230], title="週間PV推移") fig_line.show() # 3. 棒グラフ fig_bar = px.bar(x=['りんご', 'バナナ', 'いちご', 'みかん'], y=[15, 25, 18, 10], title="好きな果物") fig_bar.show()
3. DataFrame連携とカスタマイズ
color(色分け)や size(サイズ変更)を指定することで、1つのグラフに3つ以上の情報を同時に表現できます。
scores_df = pd.DataFrame({
'名前': ['A君', 'Bさん', 'C君', 'Dさん', 'Eさん'],
'国語': [82, 88, 76, 95, 65],
'数学': [78, 92, 85, 89, 72],
'理科': [85, 91, 78, 98, 68]
})
fig = px.scatter(
scores_df, x='数学', y='理科',
color='国語', size='国語', hover_name='名前',
title='科目別成績の相関(国語の点数で色とサイズ分け)'
)
fig.show()
4. 応用:タイタニック号の可視化
客室クラス別の人数と、男女別の生存率のヒストグラムを作成します。
titanic_df = pd.read_csv('https://raw.githubusercontent.com/pandas-dev/pandas/main/doc/data/titanic.csv')
titanic_df['生存状況'] = titanic_df['Survived'].map({0: '死亡', 1: '生存'})
# 1. 客室クラスごとの人数
pclass_counts = titanic_df['Pclass'].value_counts().reset_index()
pclass_counts.columns = ['客室クラス', '人数']
fig1 = px.bar(pclass_counts, x='客室クラス', y='人数', title='客室クラスごとの乗客数')
fig1.show()
# 2. 男女別の生存状況
fig2 = px.histogram(titanic_df, x='Sex', color='生存状況', barmode='group', title='男女別の生存・死亡数')
fig2.show()
第2章 実践チャレンジお題
好きな果物の棒グラフ(px.bar)で、color_discrete_sequence=['teal'] や color='x' を指定して棒の色を自分好みに変更してみましょう!
💡 ヒントを表示
fig_bar = px.bar(x=['りんご', 'バナナ', 'いちご', 'みかん'], y=[15, 25, 18, 10], color_discrete_sequence=['purple'])
scores_df を使って、x軸に『理科』、y軸に『英語』をとった散布図を作成し、グラフタイトルを設定して表示してみましょう!
💡 ヒントを表示
fig = px.scatter(scores_df, x='理科', y='英語', hover_name='名前', title='理科と英語の点数相関')
次のコードは、タイタニック号の客室クラス別年齢分布(箱ひげ図)を作成するプログラムです。しかし、このまま実行してもColab上にグラフが表示されません。画面にインタラクティブなグラフを表示するために、最後に実行すべき1行のPythonコードを正確に入力してください。
fig = px.box(titanic_df, x='Pclass', y='Age', title='客室クラス別の年齢分布')
# ★ ここに入るべき1行は何?
03. ブラウザでPythonが動く!PyScript × GitHub実践
1. サーバー不要!PyScriptって何がすごいの?
従来のWebアプリ(FlaskやDjango、Dashなど)は、月額料金がかかったりスリープしてしまう専用のバックエンドサーバー(Pythonサーバー)が必要でした。
しかし、最新の PyScript(WebAssembly技術) を使うと、「閲覧者のブラウザ上」で直接Python・Pandas・Plotlyが高速実行されます!これにより、サーバー維持費0円・スリープなし・超高速なWebアプリをHTMLだけで作れるようになります。
<!DOCTYPE html>
<html>
<head>
<title>はじめてのPyScript</title>
<!-- PyScriptの読み込み -->
<link rel="stylesheet" href="https://pyscript.net/releases/2024.1.1/core.css">
<script type="module" src="https://pyscript.net/releases/2024.1.1/core.js"></script>
</head>
<body>
<h1>ブラウザで直接動くPython</h1>
<script type="py">
from datetime import datetime
print(f"現在時刻: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
</script>
</body>
</html>
2. 本番アプリ:フロントエンドで動くGapminder分析アプリの作成
世界の国々の「一人当たりGDP」と「平均寿命」を可視化するGapminderバブルチャートアプリを作ります。HTMLのスライダーを動かすと、Python(PyScript)の関数が呼び出されてグラフがリアルタイムに更新されます!
このコードを index.html というファイル名で保存します。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Gapminder Data Dashboard</title>
<!-- Tailwind CSS -->
<script src="https://cdn.tailwindcss.com"></script>
<!-- Plotly.js -->
<script src="https://cdn.plot.ly/plotly-2.29.1.min.js"></script>
<!-- PyScript -->
<link rel="stylesheet" href="https://pyscript.net/releases/2024.1.1/core.css">
<script type="module" src="https://pyscript.net/releases/2024.1.1/core.js"></script>
</head>
<body class="bg-slate-50 p-6 flex flex-col items-center min-h-screen text-slate-800">
<div class="max-w-4xl w-full bg-white rounded-2xl p-6 shadow-md border border-slate-200">
<h1 class="text-2xl font-bold text-center text-slate-900 mb-2" id="app-title">世界の経済力と平均寿命ダッシュボード</h1>
<p class="text-xs text-center text-slate-500 mb-6">Powered by PyScript & Cloudflare Pages</p>
<!-- グラフ表示エリア -->
<div id="chart" class="w-full h-96 flex items-center justify-center bg-slate-100 rounded-xl">
<span class="text-sm text-slate-400">Pythonエンジン起動中(初回は数秒かかります)...</span>
</div>
<!-- スライダー操作 -->
<div class="mt-6 flex flex-col items-center space-y-2">
<div class="flex items-center space-x-2 font-bold text-slate-700">
<span>対象年:</span>
<span id="selected-year" class="text-orange-600 text-lg">2007</span>年
</div>
<input type="range" id="year-slider" min="1952" max="2007" step="5" value="2007" class="w-72 accent-orange-500 cursor-pointer" py-input="on_slider_change">
<span class="text-[11px] text-slate-400">※1952年から2007年まで5年刻みで移動できます</span>
</div>
</div>
<!-- ブラウザ上で動作するPythonコード -->
<script type="py" config='{"packages": ["pandas", "plotly"]}'>
import js
import json
import pandas as pd
import plotly.express as px
# Gapminderデータの読み込み
df = px.data.gapminder()
def draw_chart(year):
filtered = df[df.year == year]
fig = px.scatter(
filtered, x="gdpPercap", y="lifeExp",
size="pop", color="continent", hover_name="country",
log_x=True, size_max=60, range_x=[100, 100000], range_y=[25, 90],
title=f"{year}年の経済力と平均寿命"
)
graph_json = json.loads(fig.to_json())
js.Plotly.newPlot("chart", graph_json.get("data"), graph_json.get("layout"))
def on_slider_change(event):
val = int(event.target.value)
js.document.getElementById("selected-year").innerText = str(val)
draw_chart(val)
# 初回描画 (2007年)
draw_chart(2007)
</script>
</body>
</html>
第3章 実践チャレンジお題
HTMLの <h1 id="app-title"> の文字を自分のオリジナルタイトルに変更し、スライダーのアクセントカラー(accent-orange-500 を accent-indigo-500 など)をカスタマイズしてみましょう。
💡 ヒントを表示
<h1 class="... text-indigo-700">〇〇のGapminder探究ダッシュボード</h1>
初期表示を最新年(2007年)ではなく、最も古い年である「1952年」からスタートするように、スライダーの value="1952" と Python 内の draw_chart(1952) を書き換えてみましょう!
💡 ヒントを表示
1. <input ... value="1952">
2. <span id="selected-year">1952</span>
3. Pythonの末尾: draw_chart(1952)
スライダーを「1952年」に合わせた状態でグラフ上の「日本(Japan)」の点にカーソルを合わせるか、Colab上で df[(df.year==1952) & (df.country=='Japan')] を実行し、1952年当時の日本の平均寿命(lifeExp)の整数部分(例: 63)を入力してください。
04. Cloudflare Pagesで世界へ爆速無料公開&Webセキュリティ入門
1. GitHubへアプリを配置(Privateリポジトリの絶大な利点)
なぜGitHub Pagesではなく「Cloudflare Pages」を使うのか?
GitHub Pagesの壁: 無料プランではリポジトリを全世界に丸見えの「Public(公開)」にしなければWebサイトを公開できません。作成途中のコードやコミット履歴が世界中から見えてしまいます。
Cloudflare Pagesの決定的な強み: 無料プランでも「Private(非公開)」リポジトリと直接連携してWeb公開が可能です!生徒はGitHubのコードを非公開にしたまま、完成したWebアプリの画面だけを世界最速のCDNエッジサーバーで安全に配信できます。
- GitHub にログインし、新規リポジトリ(例:
gapminder-pyscript)を Private(非公開) で作成します。 - 先ほど作成した
index.htmlをリポジトリのルート(トップ画面)にアップロード(またはCommit)します。
💡 プロのエンジニアはどうやってるの?(ローカルIDEとGitの話)
今回の実習では、学校の端末制限やインストール作業の手間を省くため、「ブラウザのGitHub画面上でファイルを直接作成・コピペしてアップロードする」という最も手軽な方法を採用しました。
しかし、実際のソフトウェアエンジニアがGitHubのWeb画面上でポチポチコードを貼り付けて開発することはまずありません! 現場では次のようなツールを使って本格的に開発しています:
- ローカルIDE(統合開発環境)の利用: 自分のPCに VS Code(Visual Studio Code) や Cursor などの高機能エディタを入れ、シンタックスハイライト(色分け)や自動補完、AIアシスタントを活用して手元で快適にコードを書きます。
-
Gitコマンドによる厳密なバージョン管理: ターミナル(黒い画面)から
git add .➔git commit -m "機能追加"➔git push origin mainとコマンドを打ち込んでGitHubへ送信します。 - ローカルプレビュー環境: 手元のPCでローカルサーバー(`localhost:3000` など)を立ち上げ、完璧に動くことを確認してからGitHubに反映させます(本番環境の破壊を防ぐため)。
自分のPCを手に入れたり、さらに上のレベルのWeb開発を目指すときは、ぜひ「VS Codeのインストール」と「Gitコマンドでのプッシュ」に挑戦してみてください。それがプロのエンジニアへの確実な第一歩です!
2. Cloudflare Pagesでデプロイ(管理画面のUI注意点!)
⚠️ 超重要:CloudflareのUIの罠(Workersに迷い込まないで!)
Cloudflareは現在「Workers(サーバーレス関数)」を前面に推し出しているため、何も考えずにボタンを押すとWorkersの作成画面に誘導されてしまいます。
左メニューの「Workers & Pages」➔「Create application」を押したあと、画面上部のタブで必ず 「Pages」タブ をクリックして切り替えてください!その中にある「Connect to Git」を選択します。
- Cloudflareダッシュボード に無料登録・ログインします。
- 左メニューの 「Workers & Pages」➔ 「Create application」 を開きます。
- 必ず「Pages」タブを選択し、「Connect to Git」 をクリックします。
- GitHubアカウントを連携し、先ほど作成した
gapminder-pyscript(Privateリポジトリ)を選択して 「Begin setup」 をクリックします。 - ビルド設定画面では、静的HTMLなので設定を一切変更する必要がありません:
- Framework preset: None(デフォルト)
- Build command: 空欄のまま
- Build output directory: 空欄(または /)
- 「Save and Deploy」 を押すと、世界中のエッジサーバーにアプリが配備されます!
- 発行されたURL(例:
https://gapminder-pyscript.pages.dev)を開いて、スリープのない爆速のWebアプリを確認しましょう。
【プチハッキング体験】別ファイル secret.txt は本当に安全?
「GitHubをPrivate(非公開)にしたし、index.htmlとは別の secret.txt というファイルにパスコードを書いておけば、外からは見えないのでは?」
初心者が最も陥りやすいこの思い込みが、なぜ大間違いなのかを実際に自分の手でハッキング(検証)してみましょう!
- GitHubリポジトリ内に
secret.txtという新規ファイルを作成します。 - 中身に合言葉として
open-sesame-777とだけ書き、コミット(保存)します。 - Cloudflare Pagesが自動で再デプロイを完了したら、ブラウザのアドレスバーに自分の公開URLの後ろに
/secret.txtを直打ちして開いてみてください:
https://あなたのプロジェクト名.pages.dev/secret.txt - 結果はどうなりましたか? パスワードが画面に平文でそのまま表示されたはずです!
フロントエンド配信の鉄則:置いたファイルはすべて「配られる」!
Cloudflare Pagesのような静的ホスティングは、リポジトリに置いたすべてのファイルを閲覧者のブラウザへ渡す(ダウンロードさせる)仕組みです。 どれだけファイルを分けたり複雑な名前をつけても、「URL直打ち」や「F12(開発者ツールのNetworkタブ)」を開けば丸見えになります。フロントエンドには絶対に機密情報を置いてはいけません!
【本物のバックエンド構築】環境変数とPages Functionsで秘密を守る!
「じゃあ本物のWebサービスはどうやってパスワードを守っているのか?」
答えは、「ブラウザ(手元)にパスワードを渡さず、サーバー側(向こう側)の金庫で照合して、判定結果(OK/NG)だけを返す」です。
Cloudflare Pagesには最初から Pages Functions(サーバーレスバックエンド機能) が内蔵されています。コードに一切パスワードを書かず、安全なログイン認証APIを作ってみましょう。
GitHubのコードには絶対に書かず、Cloudflareダッシュボードにだけ保存します。
- Cloudflareダッシュボードで自分のPagesプロジェクトを開き、上部(または左メニュー)の 「Settings」 を選択します。
- 画面を少しスクロールし、「Variables and secrets」 の欄を見つけます。
- 右上の 「+ Add」 ボタンをクリックします。
- 項目を入力して保存します:
- Type: 「Secret」(または Plain text)
- Name:
APP_PASSWORD - Value:
pyscript999
// リポジトリ内に「functions」フォルダを作り、その中に「api」フォルダ、「check.js」を作成
// このファイルはブラウザにダウンロードされず、Cloudflareのエッジサーバー内だけで秘密裏に動きます!
export async function onRequestPost(context) {
const { request, env } = context;
const body = await request.json();
// サーバーの金庫(環境変数)と照合
const correctPassword = env.APP_PASSWORD;
const isMatched = (body.inputPassword === correctPassword);
// ブラウザには正解パスワードを教えず、「合ってるかどうか」の結果だけを返す!
return new Response(JSON.stringify({
success: isMatched,
message: isMatched ? "認証成功!秘密データを開放します。" : "合言葉が違います。"
}), {
headers: { "Content-Type": "application/json" }
});
}
<!-- 画面側のJavaScriptからサーバーへ安全に確認を依頼する処理 -->
<script>
async function verifyWithBackend(userPassword) {
const response = await fetch('/api/check', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ inputPassword: userPassword })
});
const result = await response.json();
if (result.success) {
showToast("サーバー認証成功!F12を開いてもパスワードは漏洩しません", "success");
} else {
showToast(result.message, "error");
}
}
</script>
第4章 実践チャレンジお題
GitHubリポジトリ内に README.md を作成し、「このWebアプリはPyScriptで動くGapminder可視化ダッシュボードです。制作者:〇〇」という説明を書いてみましょう。
💡 ヒントを表示
GitHubのリポジトリ画面で「Add file」➔「Create new file」を選択し、ファイル名を README.md とします。
Cloudflare Pagesで発行されたURL(https://....pages.dev)を入力欄に貼り付けて「判定する」を押してください。正当なPagesドメインであるかを自動判定します!
GitHub上の index.html のタイトル文字などを直接編集してコミットしてみてください。Cloudflare Pages側で何もボタンを押さなくても、数秒で本番サイトが自動更新されるサイクル(CI/CD)を確認できたら完了チェックを押してください。
実験①で /secret.txt にアクセスしたときに画面に表示された合言葉(パスコード文字列)を入力して判定してください。
functions/api/check.js というファイルを作った場合、ブラウザから呼び出すときの相対URL(APIのエンドポイントパス)は何になりますか?(例: /api/...)