Python相関分析入門|勉強時間と点数の関係を調べる
「2つの数字に関係があるか」を調べる方法を、身近な例で体験します
前回の記事(Pythonでデータ分析の基礎を身につける方法)では、平均・合計・グループ集計・グラフ化という基本操作を紹介しました。今回はその続編として、「2つの数字が一緒に動くかどうか」を調べる相関分析を、勉強時間と点数という身近な例で体験します。
相関分析は、日々の事務作業を自動化する話から一歩進んだ、「集めたデータから何かを言うための技術」です。売上と広告費、来客数と気温、作業時間とミスの件数——手元にある2列の数字から傾向を読み取れるようになると、報告書の説得力が変わります。
新しいライブラリのインストールは不要で、前回と同じpandas・matplotlibだけで完結します。数式も出てきません。
- 1
- 2
- 3
- 4
相関分析って何をすること?
相関分析とは、ひとことで言うと「片方の数字が大きくなると、もう片方の数字も大きくなる(または小さくなる)傾向があるか」を調べることです。たとえば、次のような組み合わせについて、なんとなく関係がありそうだと感じたことはないでしょうか。
- 勉強時間が長い人ほど、テストの点数が高い
- 気温が高い日ほど、アイスクリームの売上が伸びる
- 広告費をかけるほど、商品の売上が伸びる
相関分析を使うと、こうした「なんとなくの印象」を、具体的な数字で確認できるようになります。「関係がある気がします」と言うのと、「相関係数0.96で、強い正の相関があります」と言うのとでは、話の重みがまったく違います。
相関分析は、前回のデータ分析の基礎で学んだ「集める→整理する→傾向をつかむ」という3ステップのうち、「傾向をつかむ」をより深掘りする内容です。難しい数式は一切使いません。
用意するもの
- Python本体
- コードを書くためのエディタ(VS Codeなど)
- pandas・matplotlib
前回の記事と同じライブラリだけで進められるので、既に環境がある方は追加のインストールは不要です。まだの方は、先に「Pythonを始める前に:インストールとエディタの準備」を済ませてください。
pip install pandas matplotlib
グラフの中の日本語が豆腐のような四角(□□□)にならないようにするため、コードの中で日本語フォントを1行指定します(次の章で出てきます)。追加のライブラリは要りません。
使うデータを用意する
今回は、「勉強時間」と「テストの点数」の関係を例にします。「名前」「勉強時間」「点数」の3列だけのシンプルな形式です。
| 名前 | 勉強時間(時間) | 点数 |
|---|---|---|
| Aさん | 1 | 55 |
| Bさん | 2 | 62 |
| Cさん | 3 | 68 |
| Dさん | 3 | 74 |
| Eさん | 4 | 78 |
| Fさん | 5 | 85 |
| Gさん | 6 | 90 |
| Hさん | 6 | 83 |
CSVファイルの作り方
Excelで上の表を作り、「名前を付けて保存」でファイルの種類を「CSV UTF-8(コンマ区切り)」にして、study_scores.csvという名前で保存してください。メモ帳で直接書く場合は、次の内容をそのまま貼り付けます。
名前,勉強時間,点数
Aさん,1,55
Bさん,2,62
Cさん,3,68
Dさん,3,74
Eさん,4,78
Fさん,5,85
Gさん,6,90
Hさん,6,83
1行目の見出しは、コードの中でdf["勉強時間"]のように列を指定するときの名前になります。ここに余計なスペースが入っていると、列が見つからずエラーになります。カンマの前後は詰めて書いてください。
数字と数字の組み合わせであれば、身長と体重、広告費と売上、気温と来客数など、どんなデータでも同じ手順で分析できます。列の名前を変えるだけで、この記事のコードはそのまま使えます。
散布図で全体像をつかむ
相関係数をいきなり求める前に、まずは「散布図」を描いて目で見てみましょう。散布図は、2つの数字の組み合わせを点でプロットしたグラフです。
数字を出す前に、必ず絵で見る。これは相関分析の鉄則です。理由は後の「外れ値ひとつで、結論がひっくり返る」で分かります。
import pandas as pd
import tkinter as tk
import matplotlib
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
# グラフの日本語が□□□にならないようにする(Windows標準のフォントを指定)
matplotlib.rcParams["font.family"] = "Meiryo"
df = pd.read_csv("study_scores.csv", encoding="utf-8-sig")
fig = Figure(figsize=(6, 4))
ax = fig.add_subplot(111)
ax.scatter(df["勉強時間"], df["点数"], color="#3e8f5c", s=80)
ax.set_title("勉強時間と点数の関係")
ax.set_xlabel("勉強時間(時間)")
ax.set_ylabel("点数")
fig.tight_layout()
fig.savefig("study_scatter.png")
root = tk.Tk()
root.title("勉強時間と点数の関係")
canvas = FigureCanvasTkAgg(fig, master=root)
canvas.draw()
canvas.get_tk_widget().pack()
root.mainloop()
実行すると、点が右上がりに並んでいる様子が見えるはずです。「勉強時間が増えるほど、点数も高くなる傾向がありそうだ」ということが、数字を計算する前から視覚的に確認できます。
実際に動かすと、こうなります
点が右上がりに並んでいれば「正の相関」、右下がりに並んでいれば「負の相関」、バラバラに散らばっていれば「相関なし」の可能性が高い、というのが散布図から読み取れる大まかな目安です。
encoding="utf-8-sig"は、ExcelでCSVを保存したときに先頭に付く目に見えない印(BOM)を、正しく読み飛ばすための指定です。これを付けずにutf-8で読むと、1列目の名前が名前ではなく変な文字になり、列が見つからないエラーになります。
相関係数を求める
散布図で見た「なんとなくの傾向」を、具体的な数字にしてみます。pandasのcorr()を使うと、たった1行で相関係数が求められます。
corr = df["勉強時間"].corr(df["点数"])
print("相関係数:", round(corr, 4))
実行すると、次のように表示されます。
相関係数: 0.9637
この数字が「相関係数」で、-1から1までの範囲で、2つの数字の関係の強さを表します。1に近いほど「片方が増えると、もう片方もきれいに増える」関係が強いということです。
round(corr, 4)は小数点以下4桁に丸める指定です。付けないと0.9637139...のように長く表示されます。報告書に載せるときは、2桁(0.96)程度で十分です。
相関係数の読み方
相関係数がどのくらいの数字だと、どのくらいの関係の強さなのか、目安は以下の通りです。
| 相関係数の目安 | 関係の強さ |
|---|---|
| 0.7 ~ 1.0 | 強い正の相関 |
| 0.4 ~ 0.7 | 中くらいの正の相関 |
| 0.2 ~ 0.4 | 弱い正の相関 |
| -0.2 ~ 0.2 | ほぼ相関なし |
| -0.4 ~ -0.2 | 弱い負の相関 |
| -0.7 ~ -0.4 | 中くらいの負の相関 |
| -1.0 ~ -0.7 | 強い負の相関 |
今回の例では0.96だったので、「勉強時間と点数には強い正の相関がある」と言えそうです。数式を覚える必要はなく、この早見表と照らし合わせるだけで十分です。
相関係数は何を測っているのか
計算式を覚える必要はありませんが、何を見ている数字なのかを一言で言うと、「平均より上か下か」が2つの列で揃っているかどうかです。
勉強時間が平均より長い人は、点数も平均より高い。勉強時間が平均より短い人は、点数も平均より低い。——この「揃い方」がきれいなほど1に近づきます。逆に、勉強時間が平均より長いのに点数は平均以下、という人が混ざるほど、数字は0に近づいていきます。
相関係数が測れるのはまっすぐな関係だけです。「ある点まで増えるが、それを超えると減る」というような山型の関係は、相関係数では0に近い値になり、「関係なし」に見えてしまいます。散布図を先に見るべき理由が、ここにもあります。
外れ値ひとつで、結論がひっくり返る
ここが、この記事でいちばん覚えて帰ってほしいところです。
先ほどのデータに、たった1人を追加してみます。Iさんは9時間勉強したのですが、当日に体調を崩してしまい、45点でした。
Iさん,9,45
これをCSVに1行足して、もう一度同じコードを実行します。
相関係数: 0.0399
0.96だった相関係数が、0.04になりました。早見表で言えば「強い正の相関」から「ほぼ相関なし」への転落です。8人分のデータが示していた傾向が、1人加わっただけで消えてしまいました。
散布図で見ると、何が起きたか分かります
なぜこんなことが起きるのか
相関係数は、平均から大きく離れた点の影響を強く受けます。Iさんは「勉強時間はいちばん長いのに、点数はいちばん低い」という、それまでの傾向とまったく逆の位置にいます。こうした点は外れ値と呼ばれ、たった1つでも全体の数字を大きく動かします。
どうすればいいのか
大事なのは、外れ値を勝手に消さないことです。都合の悪い点を消せば数字はきれいになりますが、それは分析ではなく都合合わせです。やるべきことは次の順です。
- 散布図を見る — ぽつんと離れた点がないかを、目で確認する
- その点の事情を調べる — Iさんの場合は「体調不良」という理由があった
- 理由を明記したうえで判断する — 「体調不良の1名を除いた8名では0.96」と書けば、隠していることにはならない
入力ミス(点数を450と打っていた等)であれば直せばよいですし、実際に起きたことなら「そういう例もある」という情報として残します。どちらにせよ、まず気づけることが大切です。
「相関係数だけをコードで計算して、そのまま報告書に書く」というのが、いちばん危ない使い方です。数字の裏に、こういう1点が隠れているかもしれません。散布図を先に見るという手順を、必ず守ってください。
3つ以上の項目をまとめて見る
実際のデータには、列が2つだけということはあまりありません。「勉強時間」「睡眠時間」「点数」のように3つ以上ある場合、corr()を列を指定せずに使うと、すべての組み合わせを一度に計算してくれます。
print(df.corr(numeric_only=True).round(2))
ここでは、先ほどのCSVに睡眠時間の列を1つ足したデータで実行してみます(名前,勉強時間,睡眠時間,点数の4列にしたイメージです)。結果は次のような表(相関行列と呼びます)で表示されます。
勉強時間 睡眠時間 点数
勉強時間 1.00 -0.35 0.96
睡眠時間 -0.35 1.00 -0.21
点数 0.96 -0.21 1.00
表の読み方は簡単です。行と列が交わるところが、その2つの相関係数です。「勉強時間」の行と「点数」の列が交わる場所が0.96、というわけです。
斜めに並ぶ1.00は「自分自身との相関」なので、必ず1になります。ここは見なくて構いません。
numeric_only=Trueは「数字の列だけを対象にする」という指定です。名前などの文字が入った列があってもエラーにならず、自動的に除いて計算してくれます。
列が10個あれば45通りの組み合わせになります。相関行列は「どこから見ればいいか分からない大量の数字」の中から、関係が強そうな組み合わせを見つける最初の一手として使います。目星を付けたら、その2列で散布図を描く、という流れです。
注意点:相関関係は因果関係とは違う
相関分析を使ううえで、必ず知っておきたい注意点があります。それは、「相関がある」ことと「原因と結果の関係(因果関係)がある」ことは、イコールではないという点です。
よく使われる例に「アイスクリームの売上」と「水難事故の件数」があります。この2つには実は正の相関があるのですが、アイスクリームが水難事故の原因というわけではありません。どちらも「気温が高い」という共通の原因によって、一緒に増えているだけなのです。
よくある3つの勘違い
- 第三の原因がある — 上のアイスクリームの例。裏に「気温」という共通の原因が隠れている
- 因果が逆 — 「よく売れている店ほど広告費が多い」というデータを見て「広告を出せば売れる」と考える。実際は「売れているから広告費を出せる」のかもしれない
- たまたま — データが少ないと、意味のない偶然が強い相関に見えることがあります。8人程度のデータで断言しないほうが安全です
今回の「勉強時間と点数」の例でも、相関係数が高かったからといって、「勉強時間さえ増やせば必ず点数が上がる」と単純に言い切ることはできません。もともと成績のよい人が長く勉強しているだけ、という可能性も残ります。
相関分析は、あくまで「関係がありそうだ」という手がかりを見つけるための道具です。そこから先の「なぜそうなるのか」は、データの外側にある事情を調べて考えることになります。
完成版:全部つなげたコード
散布図の保存・相関係数の算出・相関行列の表示までを1つにまとめたものです。CSV_FILEと、比べたい2列の名前を書き換えれば、自分のデータでそのまま使えます。
import pandas as pd
import matplotlib
from matplotlib.figure import Figure
from pathlib import Path
# グラフの日本語が□□□にならないようにする(Windows標準のフォントを指定)
matplotlib.rcParams["font.family"] = "Meiryo"
# ==== ここを自分の内容に書き換える ====
CSV_FILE = Path("study_scores.csv")
X_COLUMN = "勉強時間"
Y_COLUMN = "点数"
OUTPUT_IMAGE = Path("scatter.png")
# ====================================
def load(path):
if not path.exists():
print(f"{path} が見つかりません")
return None
return pd.read_csv(path, encoding="utf-8-sig")
def draw_scatter(df, path):
fig = Figure(figsize=(6, 4))
ax = fig.add_subplot(111)
ax.scatter(df[X_COLUMN], df[Y_COLUMN], color="#3e8f5c", s=80)
ax.set_title(f"{X_COLUMN}と{Y_COLUMN}の関係")
ax.set_xlabel(X_COLUMN)
ax.set_ylabel(Y_COLUMN)
fig.tight_layout()
fig.savefig(path)
print(f"散布図を {path} に保存しました")
def judge(value):
v = abs(value)
if v >= 0.7:
strength = "強い"
elif v >= 0.4:
strength = "中くらいの"
elif v >= 0.2:
strength = "弱い"
else:
return "ほぼ相関なし"
direction = "正" if value > 0 else "負"
return f"{strength}{direction}の相関"
def main():
df = load(CSV_FILE)
if df is None:
return
print(f"データ件数: {len(df)} 件")
draw_scatter(df, OUTPUT_IMAGE)
corr = df[X_COLUMN].corr(df[Y_COLUMN])
print(f"{X_COLUMN} と {Y_COLUMN} の相関係数: {round(corr, 4)}")
print(f"判定: {judge(corr)}")
print("\n--- すべての組み合わせ ---")
print(df.corr(numeric_only=True).round(2))
print("\n散布図を必ず目で確認してください。")
print("ぽつんと離れた点があれば、その1件が結論を変えているかもしれません。")
if __name__ == "__main__":
main()
相関係数を出したあとに、早見表と照らして判定を日本語で表示するようにしました。数字だけだと毎回表を見に行くことになりますが、これなら実行結果をそのまま読めます。最後に散布図の確認を促すメッセージも出しています。
ここからどう学びを広げるか
今回学んだ「散布図で見る→相関係数を求める→外れ値を確認する→読み方を知る」という流れは、データ分析でとてもよく使う型です。慣れてきたら、次のようなテーマに進むと学びが広がります。
- 欠損値の処理:データの一部が空欄になっている場合の扱い方。
corr()は空欄を自動で除いて計算しますが、除いた結果が何件になったかは意識しておく必要があります - より大きなデータセットの練習:公開されている練習用データで、列が多いときの相関行列の読み方に慣れる
- 回帰分析:「関係がある」の先にある「では、勉強時間が1時間増えると点数は何点上がるのか」を求める手法
- 機械学習の入門:相関関係の先にある、予測・分類といった発展的な分野
相関分析は、機械学習に進む前の準備運動としても重要です。「どの数字とどの数字が関係していそうか」を先に把握しておくと、この先の分析がぐっとスムーズになります。
うまくいかないときのトラブルシューティング
KeyError: 勉強時間と出ます▼encoding="utf-8-sig"で読み込めば解決します。nanになります▼print(df.dtypes)で各列の種類を確認してください。数字の列なのにobjectと表示されていれば、その列のどこかに文字が入っています。全角の数字やカンマ付きの数値(1,000)もよくある原因です。matplotlib.rcParams["font.family"] = "Meiryo"の行を書き忘れていないか確認してください。この行より後でグラフを作る必要があります。順番が逆だと効きません。
Meiryoが入っていない環境では、
"MS Gothic"や"Yu Gothic"でも同じことができます。df.corr(numeric_only=True)のように列を指定せずに実行すると、すべての数値列どうしの相関係数が一覧(相関行列)で表示されます。詳しくは「3つ以上の項目をまとめて見る」で解説しています。まとめ
散布図で全体像をつかんでからcorr()で相関係数を求め、早見表で関係の強さを読み取る——という一連の流れを紹介しました。要点を整理します。
- 数字より先に、絵を見る — 散布図を描いてから相関係数を求める
- 相関係数は-1から1 — 早見表と照らすだけでよく、数式は不要
- 外れ値1つで結論は変わる — 0.96が0.04になった例のとおり。消さずに、理由を調べて明記する
- 列が多いときは相関行列 — まず全体を見て、目星を付けた2列で散布図を描く
- 相関は因果ではない — 第三の原因、逆の因果、偶然。この3つを疑う
相関分析は、「関係がありそう」という手応えを数字で裏づけるための道具です。断定するための道具ではありません。そのことさえ押さえておけば、手元のデータから言えることの幅が、確実に広がります。前回の基礎編と合わせて、小さな分析を1つずつ積み重ねていきましょう。


コメント