はい、承知いたしました。Pandasを使った散布図の基本と活用例について、詳細な説明を含む約5000語の記事を作成します。
Pandasを使った散布図の基本と活用例を紹介
はじめに:データ分析における散布図の力とPandasの役割
データ分析の旅において、数値データの関係性を理解することは非常に重要です。二つの異なる数値変数の間にどのような関連があるのか、特定のパターンは存在するのか、あるいは目立った外れ値はないか。こうした疑問に答えるための強力なツールの一つが「散布図(Scatter Plot)」です。
散布図は、二つの数値変数をそれぞれX軸とY軸に対応させ、データポイントをプロットしたグラフです。これにより、変数の間の相関関係(正の相関、負の相関、無相関)、データの分布、クラスター(集団)、そして外れ値などを直感的に把握することができます。例えば、「商品の価格が高くなるにつれて売上は増えるのか減るのか?」「従業員の経験年数と生産性には関係があるか?」「広告費用を増やせばウェブサイトへの訪問者は増えるか?」といった問いに対するヒントを得ることができます。
データ分析では、まずデータ全体の概要を掴むための「探索的データ分析(EDA: Exploratory Data Analysis)」が行われます。散布図は、このEDAにおいて中心的な役割を果たします。変数間の初期的な仮説を立てたり、さらなる詳細な分析が必要な関係性を見つけ出したりするために不可欠なグラフです。
そして、このデータ分析のプロセスにおいて、最も広く利用されているPythonライブラリの一つが「Pandas」です。Pandasは、構造化データ(表形式データ、時系列データなど)を効率的に操作・分析するための高機能なデータ構造(DataFrame, Series)を提供します。データの読み込み、クリーニング、変換、集計といった前処理作業をPandasで行い、その結果を可視化するというワークフローは、データサイエンスの現場で非常に一般的です。
Pandas DataFrameは、それ自体がplotメソッドを持っており、Matplotlibなどの可視化ライブラリと連携して様々なグラフを描画できます。散布図も例外ではありません。Pandasの.plot()メソッドを利用することで、DataFrameにあるデータを直接指定して手軽に散布図を作成できます。また、Pandas DataFrameの形式でデータを扱うことは、後述するように、散布図の各点のサイズや色を他のカラムの値に基づいて設定するなど、より複雑で情報量の多い散布図を作成する際に非常に都合が良いです。
この記事では、データ分析に必須のツールである散布図を、PythonとPandasを用いて描画する方法について、基本から応用、そして具体的な活用例までを詳細に解説します。約5000語というボリュームで、単なるコードの紹介にとどまらず、各設定の意味、描画されるグラフからの読み取り方、データ分析におけるそのグラフの役割、そして注意点までを網羅的に説明します。
さあ、Pandasを使った散布図の世界へ深く潜り込み、データに隠された洞察を引き出す力を身につけましょう。
記事の構成は以下のようになります。
- 散布図の基本:散布図とは何か、何がわかるのか
- Pandasと可視化ライブラリ:連携の仕組み
- Pandasでの基本的な散布図の描き方:
.plot.scatter()メソッドの利用 - 散布図の応用的な描画:サイズ、色、透過性などのカスタマイズ
- Pandas以外のライブラリとの連携(特にSeaborn):より高度な可視化のために
- 散布図を用いたデータ分析の活用例:具体的なシナリオとコード
- 散布図を読む上での注意点と落とし穴:相関と因果、オーバープロットなど
- まとめ:学びの振り返りと次のステップ
1. 散布図の基本:散布図とは何か、何がわかるのか
散布図(Scatter Plot)の定義と用途
散布図は、二つの数値変数間の関係を視覚化するための最も基本的なグラフの一つです。デカルト座標系(直交座標系)のX軸に一つの変数、Y軸にもう一つの変数を割り当て、各データポイント(観測値)をその二つの変数の値に基づいてプロットします。
用途としては、主に以下のような場面で活用されます。
- 変数間の関係性の探索: 二つの変数が互いにどのように影響し合っているか(またはいないか)を視覚的に確認します。
- 相関関係の発見: 正の相関(片方が増えると他方も増える)、負の相関(片方が増えると他方が減る)、あるいは無相関(関係がない)といった線形な関係性を視覚的に判断できます。
- データの分布やクラスターの確認: データポイントがどのようにばらついているか、特定の領域に集中している集団があるかなどを把握します。
- 外れ値(Outliers)の特定: 他のデータポイントから大きくかけ離れた位置にある点を見つけ出します。これらの外れ値は、データ入力のエラーである可能性もあれば、分析上非常に重要な意味を持つ特別な観測値である可能性もあります。
散布図でわかること:相関、分布、外れ値
散布図を見ることで、具体的にどのような情報を読み取ることができるのでしょうか。
- 相関の方向と強さ:
- 正の相関: データポイントが右上がりの帯状に分布している場合、二つの変数には正の相関があります。Xの値が増加すると、Yの値も増加する傾向が見られます。例:「勉強時間」と「試験の成績」。
- 負の相関: データポイントが右下がりの帯状に分布している場合、二つの変数には負の相関があります。Xの値が増加すると、Yの値は減少する傾向が見られます。例:「製品価格」と「需要量」。
- 無相関: データポイントが特定の方向性なく、全体に均等にばらついている場合、二つの変数間に明確な線形な相関はないと考えられます。例:「靴のサイズ」と「年収」。
- 相関の強さ: 帯状のばらつきが少ない(点が線に近い)ほど相関は強く、ばらつきが大きいほど相関は弱いです。相関の強さは、相関係数(-1から1の値を取り、1または-1に近いほど強い相関を示す)といった統計的な指標で定量化することもできますが、散布図はそれを視覚的に捉えるのに役立ちます。
- 非線形な関係性: 散布図は線形な相関だけでなく、曲線的な関係性(例:ある値までは増加するが、それを超えると減少に転じる)なども視覚的に発見するのに有効です。
- データの分布: データポイントがX軸、Y軸それぞれでどのような範囲に分布しているか、特定の範囲にデータが密集しているかなどを把握できます。
- クラスター: 散布図上に複数のデータポイントの集団(クラスター)が確認できる場合、それはデータの中に異なる特性を持つサブグループが存在する可能性を示唆します。例えば、顧客データにおいて、年齢と購入金額の散布図で二つの異なる集団が見られるなら、それは異なる顧客セグメントかもしれません。
- 外れ値: 他の多くのデータポイントから離れた位置にある点は外れ値の候補です。外れ値は分析結果に大きな影響を与える可能性があるため、その原因を調査し、必要に応じて適切に処理(除外、修正など)することが重要です。散布図は外れ値を視覚的に特定するのに非常に有効です。
なぜPandasを使って散布図を描くのか?
Pandasはデータ分析における中心的なツールであり、そのDataFrame構造は散布図を描画するのに理想的です。
- データの整合性: DataFrameはカラム名を持つ構造化データであるため、X軸とY軸に対応させるカラムを名前で指定できます。これにより、どのカラムをプロットしているのかが明確になり、コードの可読性が高まります。
- データ前処理との統合: 散布図を描画する前に、Pandasを使ってデータのフィルタリング、変換、新しい特徴量の作成などの前処理を行うことが一般的です。Pandas DataFrame上でこれらの作業を行い、そのまま同じDataFrameオブジェクトに対して
.plot()メソッドを呼び出すことで、データ分析のワークフローが非常にスムーズになります。 - 他のカラム情報の利用: Pandas DataFrameには複数のカラムが存在します。散布図において、単にXとYだけでなく、データポイントのサイズや色をDataFrame内の他のカラムの値(例えば、データの「重み」や「カテゴリ」)に基づいて設定することで、三次元以上の情報を二次元の散布図にエンコードし、より多くの洞察を得ることができます。Pandasの
.plot.scatter()メソッドは、これらの情報を引数として渡すことで簡単に実現できます。 - 様々な可視化ライブラリとの連携: Pandasの
.plot()メソッドは、内部的にMatplotlibを使用しています。したがって、Pandasで描画したグラフに対して、Matplotlibの機能(軸ラベル、タイトル、凡例、アノテーションなど)を追加でカスタマイズすることが容易です。また、Pandas DataFrameはSeabornのような他の高度な可視化ライブラリとも非常に親和性が高く、Pandasで前処理したデータをそのままSeabornに渡してさらに洗練されたグラフを描画することも一般的です。
このように、Pandasを使うことで、データ操作から可視化までを一貫して効率的に行うことができ、データ分析の強力な基盤となります。
2. Pandasと可視化ライブラリ:連携の仕組み
Pandas自体はデータ操作・分析ライブラリですが、データの視覚化機能も提供しています。Pandasの.plot()メソッドは、その便利なインターフェースを通じて、データ可視化ライブラリの機能を利用しています。最も一般的には、PandasはバックエンドとしてMatplotlibを使用します。
Pandas DataFrameやSeriesオブジェクトは、それぞれ.plot()メソッドを持っています。このメソッドは、データの内容や指定された引数に応じて、様々な種類のグラフ(折れ線グラフ、棒グラフ、ヒストグラム、箱ひげ図、そして散布図など)を描画することができます。
散布図を描画する場合、DataFrameの.plot.scatter()メソッドを使用するのが最も直接的な方法です。例えば、df.plot.scatter(x='column_x', y='column_y')のように記述します。この記述は、内部的にはMatplotlibのAxes.scatter()関数を呼び出しており、PandasがDataFrameから指定されたカラムのデータを取り出し、Matplotlib関数に適切な形式で渡しています。
“`python
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
サンプルデータの作成
np.random.seed(0)
df_sample = pd.DataFrame({
‘X_Value’: np.random.rand(100) * 100,
‘Y_Value’: np.random.rand(100) * 50 + 2 * np.random.rand(100) * 100,
‘Category’: np.random.choice([‘A’, ‘B’, ‘C’], 100),
‘Size_Value’: np.random.rand(100) * 200 + 50, # サイズを変えるためのカラム
‘Color_Value’: np.random.rand(100) * 10 # 色を変えるためのカラム
})
Pandasのplotメソッドを使って散布図を描画
内部的にはMatplotlibが使われる
ax = df_sample.plot.scatter(x=’X_Value’, y=’Y_Value’, title=’Basic Scatter Plot with Pandas’)
plt.show()
“`
上記のコードでは、df_sample.plot.scatter()を呼び出しています。このメソッドはMatplotlibのAxesオブジェクトを返します。したがって、描画後にMatplotlibの機能を使ってさらにカスタマイズすることも可能です。例えば、ax.set_xlabel(...), ax.set_title(...)のようにメソッドチェーンでカスタマイズしたり、描画後にplt.title(...)やplt.xlabel(...)などMatplotlibのステートベースのインターフェースを使ったりすることもできます。
一方、SeabornもPandas DataFrameとの親和性が非常に高い可視化ライブラリです。SeabornはMatplotlibを基盤としていますが、より統計的なグラフの描画に特化しており、美しいデフォルトスタイルや複雑なグラフを少ないコードで描くための高レベルなインターフェースを提供します。特に、カテゴリ変数によるデータのグループ分け(色分けやマーカー分けなど)はSeabornの得意とするところです。
例えば、Seabornで散布図を描くにはseaborn.scatterplot()関数を使用します。これもPandas DataFrameを直接引数として渡すことができます。
“`python
import seaborn as sns
import matplotlib.pyplot as plt
上記で作成した df_sample を使用
plt.figure(figsize=(8, 6)) # Matplotlibを使って図のサイズを指定
sns.scatterplot(data=df_sample, x=’X_Value’, y=’Y_Value’, hue=’Category’) # Seabornのscatterplot
plt.title(‘Scatter Plot with Seaborn (Colored by Category)’)
plt.show()
“`
この例では、Seabornのscatterplot関数にdata=df_sampleとDataFrameを渡し、hue='Category'と指定することで、’Category’カラムの値に基づいて点の自動的に色分けし、凡例を追加してくれます。これはPandasの.plot.scatter()では少し手間がかかる処理です(後述の応用編でPandasでの実現方法も説明しますが、Seabornの方が直感的です)。
Pandas .plot.scatter() と Seaborn scatterplot() の使い分けの考え方:
- Pandas
.plot.scatter():- 最も基本的な散布図を手軽に描きたい場合。
- Pandasでのデータ前処理の直後に、同じDataFrameオブジェクトからすぐにプロットしたい場合。
- Matplotlibの機能を直接的に使って細かくカスタマイズしたい場合(
.plot()メソッドがMatplotlib Axesオブジェクトを返すため)。 - サイズや色などのカスタマイズも可能だが、カテゴリ変数による色分けなどはSeabornに比べてやや手動での設定が必要。
- Seaborn
scatterplot():- カテゴリ変数に基づいて色分け、サイズ分け、スタイル分けなどをしたい場合。
- 統計的な観点からデータの関係性をより深く探りたい場合(例: 回帰直線、信頼区間の表示など)。
- より洗練されたデザインのグラフをデフォルトで得たい場合。
- Pandas DataFrameとの連携が非常にスムーズ。
この記事では、Pandasの.plot.scatter()を中心に解説を進めますが、Seabornが提供する追加機能についても簡単に触れることで、より幅広い散布図の描画に対応できるようにします。
3. Pandasでの基本的な散布図の描き方:.plot.scatter()メソッドの利用
Pandas DataFrameを使用して散布図を描画する最も基本的な方法は、DataFrameオブジェクトの.plotアクセサを通じて.scatter()メソッドを呼び出すことです。
必要なライブラリのインポート
まず、Pandasと、描画のためにPandasが内部的に使用するMatplotlibのpyplotモジュールをインポートします。
python
import pandas as pd
import numpy as np # サンプルデータ作成用
import matplotlib.pyplot as plt
Jupyter NotebookやGoogle Colabなどの環境では、グラフをセル内に表示するために%matplotlib inlineを記述することが一般的です(環境によっては不要な場合もあります)。
python
%matplotlib inline
サンプルデータの作成
ここでは、説明のためにシンプルなDataFrameを作成します。例えば、架空の学生の「勉強時間(hours_studied)」と「試験の点数(exam_score)」の関係を見るためのデータを作成してみましょう。
“`python
サンプルデータの作成
data = {
‘hours_studied’: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5, 0.5,
3, 6, 9, 2, 5, 8, 1, 4, 7, 10,
0.8, 1.8, 2.8, 3.8, 4.8, 5.8, 6.8, 7.8, 8.8, 9.8],
‘exam_score’: [40, 50, 60, 65, 70, 75, 80, 85, 90, 95,
45, 55, 62, 68, 72, 78, 82, 88, 92, 35,
58, 76, 91, 48, 71, 86, 42, 67, 81, 94,
38, 49, 59, 66, 69, 74, 79, 84, 89, 93]
}
df = pd.DataFrame(data)
print(df.head())
“`
| hours_studied | exam_score | |
|---|---|---|
| 0 | 1 | 40 |
| 1 | 2 | 50 |
| 2 | 3 | 60 |
| 3 | 4 | 65 |
| 4 | 5 | 70 |
このDataFrame df には、hours_studiedとexam_scoreという2つの数値カラムがあります。これらを使って散布図を描いてみましょう。
df.plot.scatter(x='カラム名', y='カラム名') の基本的な使い方
DataFrame df の.plot.scatter()メソッドを呼び出し、X軸とY軸に対応させるカラム名をそれぞれx引数とy引数に文字列で指定します。
“`python
基本的な散布図の描画
df.plot.scatter(x=’hours_studied’, y=’exam_score’)
グラフを表示
plt.title(‘Study Hours vs Exam Score’) # タイトルを追加(Matplotlib関数を使用)
plt.xlabel(‘Hours Studied’) # X軸ラベルを追加
plt.ylabel(‘Exam Score’) # Y軸ラベルを追加
plt.grid(True) # グリッド線を追加
plt.show()
“`
コードの説明:
df.plot.scatter(): DataFramedfの.plotアクセサを通じて散布図描画メソッドを呼び出しています。x='hours_studied': DataFrameのhours_studiedカラムをX軸の値として使用することを指定しています。y='exam_score': DataFrameのexam_scoreカラムをY軸の値として使用することを指定しています。plt.title(...),plt.xlabel(...),plt.ylabel(...),plt.grid(True): これらの行はMatplotlibのpyplotモジュールの関数です。Pandasの.plot()メソッドは内部でMatplotlibを使用するため、描画後にこれらの関数を使ってグラフのタイトル、軸ラベル、グリッド線などを追加・カスタマイズできます。plt.show(): 描画されたグラフを表示します。
実行結果(図の説明):
このコードを実行すると、横軸に「勉強時間」、縦軸に「試験の点数」をとった散布図が表示されます。各点は、DataFrameの1行に対応しており、その学生の勉強時間と試験の点数の組み合わせを示します。
図を見ると、データポイントが右上がりの傾向を示していることがわかります。つまり、「勉強時間が増えるにつれて、試験の点数も高くなる」という正の相関があることが視覚的に確認できます。点のばらつき具合から、相関の強さもある程度把握できます(この例では比較的強い正の相関が見られます)。
figsize引数によるグラフサイズの調整
グラフのサイズは、figsize引数を使って調整できます。これはタプルで(幅, 高さ)をインチ単位で指定します。
“`python
グラフサイズを指定して描画
df.plot.scatter(x=’hours_studied’, y=’exam_score’, figsize=(10, 6)) # 幅10インチ、高さ6インチ
plt.title(‘Study Hours vs Exam Score (Custom Size)’)
plt.xlabel(‘Hours Studied’)
plt.ylabel(‘Exam Score’)
plt.grid(True)
plt.show()
“`
figsizeを指定することで、図が大きくなり、データポイントが見やすくなる場合があります。特にデータポイントが多い場合や、詳細な情報(後述するサイズや色分けなど)を盛り込む場合は、適切なサイズに調整することが重要です。
軸の範囲設定 (xlim, ylim)
X軸およびY軸の表示範囲を限定したい場合は、xlimとylim引数を使用します。それぞれの引数には、タプルやリストで(最小値, 最大値)を指定します。
“`python
軸の範囲を限定して描画
df.plot.scatter(x=’hours_studied’, y=’exam_score’, xlim=(0, 12), ylim=(30, 100)) # X軸を0から12、Y軸を30から100に設定
plt.title(‘Study Hours vs Exam Score (Limited Axes)’)
plt.xlabel(‘Hours Studied’)
plt.ylabel(‘Exam Score’)
plt.grid(True)
plt.show()
“`
軸の範囲を限定することで、特定の範囲に焦点を当てたり、見たい部分を拡大して表示したりすることができます。ただし、範囲を極端に設定しすぎると、データ全体の分布やつながりが見えにくくなることがあるため注意が必要です。
このように、Pandasの.plot.scatter()メソッドは、非常に少ないコードでDataFrameから直接散布図を描画できる強力な機能を提供します。基本的な描画に加えて、Matplotlibと連携することで、タイトルや軸ラベル、グリッド線などの基本的なカスタマイズも容易に行えます。
4. 散布図の応用的な描画:サイズ、色、透過性などのカスタマイズ
基本的な散布図では、各データポイントは同じサイズ、同じ色の点で表示されます。しかし、散布図にはX軸とY軸の2つの変数だけでなく、3つ目、4つ目の変数情報を含めることで、より多くの情報を一度に視覚化するテクニックがあります。これは「多変量散布図」とも呼ばれます。Pandasの.plot.scatter()メソッドは、これらの応用的な描画をサポートするための引数を提供しています。
点のサイズを変える (s引数)
s引数を使うと、各データポイントのサイズを制御できます。sには単一の数値を指定すると全ての点のサイズがその値になりますが、DataFrameの数値カラム名を指定すると、そのカラムの値に応じて点のサイズが自動的にスケーリングされます。
サンプルデータ df_sample には Size_Value というサイズを変えるためのカラムが含まれています。これを使って散布図を描いてみましょう。
“`python
サイズを変えるための散布図
Size_Value カラムの値に応じて点のサイズが変わる
df_sample.plot.scatter(x=’X_Value’, y=’Y_Value’, s=’Size_Value’, title=’Scatter Plot with Variable Point Size’)
plt.xlabel(‘X Value’)
plt.ylabel(‘Y Value’)
plt.show()
“`
コードの説明:
s='Size_Value':s引数にDataFrameのカラム名'Size_Value'を指定しています。これにより、Size_Valueの値が大きいデータポイントほど、散布図上の点が大きく描画されます。
実行結果(図の説明):
この散布図では、X軸とY軸の関係に加え、点の大きさから3つ目の変数Size_Valueの値も読み取ることができます。例えば、図の右下の方にある大きな点は、X_Valueは大きいがY_Valueは比較的小さく、かつSize_Valueが大きいデータポイントである、といった情報を同時に得られます。これにより、変数間の関係性が他の変数によってどのように影響されるか、といった洞察を得やすくなります。
点の色を変える (c引数)
c引数を使うと、各データポイントの色を制御できます。cには様々な指定方法があります。
- 単一色の指定: 文字列(例:
'red','blue')やRGBAタプル(例:(0, 0, 1, 1)で青)を指定すると、全ての点がその色になります。 - 数値カラムによる色のグラデーション: DataFrameの数値カラム名を指定すると、そのカラムの値に応じて点の色のグラデーションが自動的に適用されます。これはヒートマップのような色のスケールで、値の大小を色の濃淡などで表現します。
- カテゴリカルカラムによる色分け: 直接カテゴリカルカラム名を指定することはできません(文字列として扱われてしまいます)。カテゴリ変数で色分けしたい場合は、そのカテゴリを数値にマッピングした新しいカラムを作成するか、後述するようにSeabornを利用するのが一般的です。ただし、Pandasの
.plotメソッドでは、cにカテゴリリスト(数値にマッピング済み)を渡し、cmap引数でカラーマップを指定することで、カテゴリごとの色分けに近いことを実現できます(少し手間がかかります)。
サンプルデータ df_sample には Color_Value (数値) と Category (カテゴリカル) の両方のカラムが含まれています。
数値カラムによる色のグラデーション
c引数に数値カラム名'Color_Value'を指定してみましょう。さらに、グラデーションの色合いを決めるためのcmap引数でカラーマップを指定できます。代表的なカラーマップには'viridis', 'plasma', 'Blues', 'Reds'などがあります。カラーバーを表示するには、colorbar=Trueを指定します。
“`python
数値カラムによる色のグラデーション
Color_Value カラムの値に応じて点の色の濃淡が変わる
df_sample.plot.scatter(x=’X_Value’, y=’Y_Value’, c=’Color_Value’, cmap=’viridis’, colorbar=True, title=’Scatter Plot with Color Gradient’)
plt.xlabel(‘X Value’)
plt.ylabel(‘Y Value’)
plt.show()
“`
コードの説明:
c='Color_Value':c引数に数値カラム名'Color_Value'を指定。このカラムの値の大小が色の濃淡や色相の変化にマッピングされます。cmap='viridis': 使用するカラーマップを指定します。'viridis'は連続的な数値を表現するのに適したカラーマップの一つです。colorbar=True: グラフの横にカラーバーを表示することを指定します。カラーバーは、色のグラデーションがColor_Valueのどの範囲に対応するかを示します。
実行結果(図の説明):
この散布図では、X軸とY軸の関係に加えて、点の色の違いから4つ目の変数Color_Valueの値も読み取れます。カラーバーを見ることで、例えば「黄色い点」はおおよそColor_Valueが8〜10の範囲にあるデータポイントである、といったことがわかります。これにより、XとYの関係性が、Color_Valueの値によってどのように異なるか、といった洞察を得ることができます。
カテゴリカルカラムによる色分け (Pandasでの工夫)
Pandasの.plot.scatter()メソッドでカテゴリカルデータを直接cに指定しても意図した色分けにはなりません。しかし、カテゴリごとにループ処理を行うか、カテゴリを数値にマッピングしてcに渡し、cmapと組み合わせることで実現可能です。ここでは、カテゴリごとにループしてプロットする方法を紹介します。
“`python
カテゴリごとに色分けしてプロット (Pandasのplotメソッド内でループ)
fig, ax = plt.subplots(figsize=(8, 6)) # MatplotlibでFigureとAxesを作成
categories = df_sample[‘Category’].unique() # カテゴリの一覧を取得
colors = [‘red’, ‘blue’, ‘green’] # 各カテゴリに割り当てる色
for i, category in enumerate(categories):
# 各カテゴリに属するデータのみをフィルタリング
df_subset = df_sample[df_sample[‘Category’] == category]
# サブセットに対して散布図をプロット
# ax引数で既存のAxesオブジェクトを指定して同一グラフに描画
df_subset.plot.scatter(x=’X_Value’, y=’Y_Value’, ax=ax, color=colors[i], label=category)
ax.set_title(‘Scatter Plot Colored by Category (Pandas Loop)’)
ax.set_xlabel(‘X Value’)
ax.set_ylabel(‘Y Value’)
ax.legend(title=’Category’) # 凡例を表示
ax.grid(True)
plt.show()
“`
コードの説明:
fig, ax = plt.subplots(...): Matplotlibを使って、プロット先の図(Figure)と軸(Axes)オブジェクトを明示的に作成します。これにより、複数のプロットを同じAxes上に重ねて描画できます。categories = df_sample['Category'].unique():Categoryカラムに含まれるユニークなカテゴリ名のリストを取得します。colors = ['red', 'blue', 'green']: 各カテゴリに対応させる色のリストを定義します。カテゴリ数と色の数が一致している必要があります。for ... in enumerate(categories):: 各カテゴリに対してループ処理を行います。df_subset = df_sample[df_sample['Category'] == category]: 現在のカテゴリに属する行だけをフィルタリングして新しいDataFrame(サブセット)を作成します。df_subset.plot.scatter(..., ax=ax, color=colors[i], label=category): フィルタリングしたサブセットに対して.plot.scatter()を呼び出します。ax=ax: 描画先のAxesオブジェクトとして、ループの前に作成したaxを指定します。これにより、全てのカテゴリの点が同じグラフ上に描画されます。color=colors[i]: 現在のカテゴリに対応する色をcolor引数で指定します。label=category: そのカテゴリの凡例ラベルをlabel引数で指定します。
ax.legend(): 凡例を表示します。各.plot.scatter()呼び出しで指定したlabelが凡例として使用されます。
実行結果(図の説明):
この方法では、Categoryカラムのユニークな値ごとに異なる色の点が描画され、凡例が表示されます。これにより、カテゴリごとにXとYの関係性や分布がどのように異なるかを比較することができます。例えば、カテゴリAのデータはXとYに強い正の相関が見られるが、カテゴリBは無相関に近い、といった違いが視覚的に把握できます。ただし、この方法はコードが少し複雑になり、色の自動割り当てや凡例の管理がSeabornに比べて手動になります。
透過性の設定 (alpha引数)
データポイントの数が多い場合、点が互いに重なり合ってしまい、データの密度や分布がわかりにくくなることがあります(オーバープロット問題)。このような場合、alpha引数を使って点の透過性を設定すると効果的です。alphaは0(完全に透明)から1(完全に不透明)の間の値を指定します。値が小さいほど透過性が高くなります。
データポイントが多い場合のサンプルデータを作成してみましょう。
“`python
データポイントが多い場合のサンプルデータ
np.random.seed(1)
df_large = pd.DataFrame({
‘X_Value’: np.random.rand(5000) * 100,
‘Y_Value’: np.random.rand(5000) * 100 + np.random.randn(5000) * 20
})
透過性なしで描画
df_large.plot.scatter(x=’X_Value’, y=’Y_Value’, title=’Scatter Plot without Transparency (Overplotting)’)
plt.show()
透過性をつけて描画
df_large.plot.scatter(x=’X_Value’, y=’Y_Value’, alpha=0.3, title=’Scatter Plot with Transparency (alpha=0.3)’) # alpha=0.3を設定
plt.show()
“`
コードの説明:
alpha=0.3: 透過性を0.3に設定しています。点が半透明になるため、重なり合った部分は色が濃くなり、データの密集度合いを視覚的に把握しやすくなります。
実行結果(図の説明):
透過性なしの図では、多くの点が重なり合い、どこにデータが集中しているのかが分かりにくいです。一方、透過性ありの図では、データポイントが密集している領域(色が濃くなっている部分)と、そうでない領域(色が薄い部分)が明確になり、データの分布や密度構造をより正確に把握することができます。オーバープロット問題に対処するための非常に有効な手段です。
マーカーの変更 (marker引数)
データポイントの形状(マーカー)を変更したい場合は、marker引数を使用します。一般的なマーカーの種類には、'o'(円、デフォルト)、'.'(点)、'x'(バツ印)、'+'(プラス)、'*'(アスタリスク)、's'(四角)、'D'(ひし形)などがあります。
“`python
マーカーを変更して描画
df_sample.plot.scatter(x=’X_Value’, y=’Y_Value’, marker=’X’, color=’purple’, s=50, title=’Scatter Plot with Custom Marker’) # マーカーを’x’に変更
plt.xlabel(‘X Value’)
plt.ylabel(‘Y Value’)
plt.show()
“`
コードの説明:
marker='X': マーカーを大きなバツ印に変更しています。color='purple': 点の色を単一の紫に指定しています。
実行結果(図の説明):
各データポイントがバツ印で表示されます。マーカーの種類を変えることで、複数の散布図を同じグラフに重ねて描画した際に、異なるデータ系列を区別しやすくするなどの用途があります。
複数の散布図を同一グラフに描画する方法
上でカテゴリごとに色分けした例でも少し触れましたが、Pandasの.plot()メソッドは、MatplotlibのAxesオブジェクトをax引数として受け取ることで、既存のグラフに追加して描画することができます。これを利用して、複数のデータ系列や異なる変数間の散布図を同じグラフ上に重ねて表示できます。
ここでは、サンプルデータ df に新しいカラムを追加し、異なるグループの散布図を重ねて描画する例を示します。
“`python
複数の散布図を同一グラフに描画するサンプルデータ
df_multi = pd.DataFrame({
‘X1’: np.random.rand(50) * 10,
‘Y1’: np.random.rand(50) * 10 + df_large[‘X_Value’].iloc[:50] * 0.8,
‘X2’: np.random.rand(50) * 10 + 5,
‘Y2’: np.random.rand(50) * 10 – df_large[‘X_Value’].iloc[50:100].values * 0.5 + 80 # 負の相関
})
MatplotlibでFigureとAxesを作成
fig, ax = plt.subplots(figsize=(8, 6))
1つ目の散布図を描画
df_multi.plot.scatter(x=’X1′, y=’Y1′, ax=ax, color=’blue’, label=’Series 1′)
2つ目の散布図を同じAxesに描画
df_multi.plot.scatter(x=’X2′, y=’Y2′, ax=ax, color=’red’, label=’Series 2′, marker=’^’)
ax.set_title(‘Multiple Scatter Plots on One Figure’)
ax.set_xlabel(‘X Value’)
ax.set_ylabel(‘Y Value’)
ax.legend() # 凡例を表示
ax.grid(True)
plt.show()
“`
コードの説明:
fig, ax = plt.subplots(...): 描画先のAxesオブジェクトaxを事前に作成します。df_multi.plot.scatter(..., ax=ax, ...): 1つ目の散布図をaxに描画します。colorとlabelで色と凡例ラベルを指定。df_multi.plot.scatter(..., ax=ax, ...): 2つ目の散布図を同じaxに描画します。異なるcolor,label,markerを指定することで、2つのデータ系列を区別できるようにします。ax.legend(): 凡例を表示します。各plot.scatter呼び出しで指定したlabelが凡例項目としてリストされます。
実行結果(図の説明):
一つのグラフ上に、青い丸で示されるデータ系列1(おそらく正の相関)と、赤い上向き三角で示されるデータ系列2(おそらく負の相関)が重ねて描画されます。このように異なるデータセットや異なる変数間の関係性を一つの図で比較する際に、複数の散布図を重ねる手法は有効です。
対数スケール (logx, logy)
変数の中には、値の範囲が非常に広いもの(例えば、収入、人口、特定の測定値など)があります。このようなデータをそのまま線形スケールでプロットすると、値の小さい部分のデータポイントが密集して見えにくくなることがあります。このような場合、X軸またはY軸、あるいはその両方を対数スケールで表示することで、データ分布をより均等に見せたり、指数関数的な関係性を線形に見せたりすることができます。
Pandasの.plot.scatter()メソッドは、logx=Trueまたはlogy=True引数を提供しています。
“`python
対数スケールのサンプルデータ
np.random.seed(2)
df_log = pd.DataFrame({
‘X_Value_Large’: np.random.rand(100) * 10000, # 広い範囲の値
‘Y_Value_Expo’: np.exp(np.random.rand(100) * 5) + np.random.randn(100) * 10 # 指数関数的な関係 + ノイズ
})
線形スケールで描画
df_log.plot.scatter(x=’X_Value_Large’, y=’Y_Value_Expo’, title=’Scatter Plot (Linear Scale)’)
plt.show()
対数スケールで描画
df_log.plot.scatter(x=’X_Value_Large’, y=’Y_Value_Expo’, logx=True, logy=True, title=’Scatter Plot (Log-Log Scale)’) # 両軸を対数スケールに
plt.show()
“`
コードの説明:
logx=True,logy=True: それぞれX軸、Y軸を対数スケールで表示することを指定します。
実行結果(図の説明):
線形スケールの図では、多くのデータポイントが原点付近に密集し、Y軸の値が大きい一部の点だけが上の方に散らばっているように見えます。データの分布が偏って見えます。
一方、対数スケールの図では、軸の目盛りが対数的に(例えば1, 10, 100, 1000のように)変化し、値の小さい部分から大きい部分までが比較的均等な間隔で表示されます。この例では、対数スケールにすることでデータポイントがおおよそ線形に分布しているように見え、変数間の指数関数的な関係性が直線として捉えやすくなっています。データのスケールが広い場合や、比率・増殖率に関わるデータを扱う場合に、対数スケールは有効な選択肢となります。
5. Pandas以外のライブラリとの連携(特にSeaborn)
前述のように、Pandasの.plot()メソッドはMatplotlibを基盤としていますが、より高度な統計的可視化や、カテゴリ変数によるグループ分けなどを容易に行うためには、Seabornが非常に強力な選択肢となります。SeabornはPandas DataFrameとの親和性が非常に高く設計されており、多くの関数がDataFrameを直接入力として受け付け、カラム名を指定するだけで複雑なグラフを作成できます。
ここでは、Pandasの.plot.scatter()では少し工夫が必要だったカテゴリ変数による色分けを、Seabornのscatterplot関数を使って簡単に行う方法を紹介します。
“`python
import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
サンプルデータの作成 (カテゴリ変数を含む)
np.random.seed(0)
df_seaborn = pd.DataFrame({
‘X_Value’: np.random.rand(100) * 100,
‘Y_Value’: np.random.rand(100) * 50 + 2 * np.random.rand(100) * 100,
‘Category’: np.random.choice([‘A’, ‘B’, ‘C’], 100),
‘Numeric_Color’: np.random.rand(100) * 10,
‘Size_Value’: np.random.rand(100) * 200 + 50
})
plt.figure(figsize=(10, 7)) # Matplotlibの機能を使って図のサイズを設定
Seabornのscatterplot関数を使用
data: プロットに使用するDataFrame
x, y: X軸、Y軸に対応するカラム名
hue: 色分けに使用するカラム名 (カテゴリでも数値でも可)
size: サイズ変更に使用するカラム名
style: マーカー変更に使用するカラム名 (通常カテゴリ変数)
sns.scatterplot(data=df_seaborn,
x=’X_Value’,
y=’Y_Value’,
hue=’Category’, # カテゴリで色分け
size=’Size_Value’, # 数値カラムでサイズ変更
alpha=0.7) # 透過性も指定可能
plt.title(‘Scatter Plot with Seaborn (Hue, Size)’)
plt.xlabel(‘X Value’)
plt.ylabel(‘Y Value’)
plt.grid(True)
plt.show()
“`
コードの説明:
sns.scatterplot(...): Seabornのscatterplot関数を呼び出しています。data=df_seaborn: プロット対象のPandas DataFrameを指定します。x='X_Value',y='Y_Value': X軸、Y軸のカラム名を指定します。hue='Category':Categoryカラムに基づいて点を色分けします。Seabornが自動的に各カテゴリに異なる色を割り当て、凡例を作成してくれます。size='Size_Value':Size_Valueカラムの値に基づいて点のサイズを変化させます。これもSeabornが自動的にスケーリングと凡例を行ってくれます。alpha=0.7: 透過性を指定します。
実行結果(図の説明):
この散布図は、Pandasの.plot.scatter()で一つずつ設定するよりも少ないコードで、カテゴリごとの色分けと数値によるサイズ変更を同時に実現しています。凡例も色分けとサイズ変更の両方について自動的に追加されており、非常に情報量の多いグラフを手軽に作成できます。
Seabornは他にも、線形回帰直線を superimposed した散布図(regplot)や、複数の変数間の散布図行列(pairplot)など、データ分析に役立つ様々な散布図関連の機能を提供しています。
Pandasの.plot.scatter()は手軽で基本的な描画に適しており、Seabornはより洗練されたデザインや統計的な視点からの多変量プロットに強みがあります。状況に応じてこれらのライブラリを使い分ける、あるいは組み合わせて使用することが、効果的なデータ可視化には重要です。
6. 散布図を用いたデータ分析の活用例:具体的なシナリオとコード
ここでは、実際のデータ分析のシナリオを想定し、Pandasを使った散布図がどのように活用できるか、具体的なデータ作成からプロット、そして読み取り方までを詳細に解説します。
例1: 住宅価格データ分析 – 広さと価格の関係性
シナリオ: ある地域の住宅販売データがあります。住宅の広さと販売価格の間にどのような関係があるか、また、築年数や地域によってその関係性に違いがあるかを知りたいです。散布図を使って探索的な分析を行います。
使用するデータ: 架空の住宅販売データ。カラムとして「広さ(平方メートル)」「価格(万円)」「築年数(年)」「地域(A, B, C)」を持ちます。
データ作成:
“`python
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns # Seabornも併用
np.random.seed(42) # 再現性のためのシード設定
架空の住宅販売データを作成
n_houses = 200
area = np.random.rand(n_houses) * 150 + 50 # 広さ: 50~200 sqm
age = np.random.rand(n_houses) * 40 + 5 # 築年数: 5~45 年
価格は広さに比例し、築年数に反比例する傾向に地域による差を考慮
region = np.random.choice([‘A’, ‘B’, ‘C’], n_houses, p=[0.4, 0.3, 0.3])
price = 300 + area * 5 + age * (-2) + np.random.randn(n_houses) * 100 # 基本的な価格モデルにノイズ
地域Aは価格が高め、地域Cは価格が低めと仮定して調整
price[region == ‘A’] = 1.2
price[region == ‘C’] = 0.8
df_housing = pd.DataFrame({
‘Area_sqm’: area,
‘Age_years’: age,
‘Region’: region,
‘Price_JPY’: price
})
print(df_housing.head())
“`
| Area_sqm | Age_years | Region | Price_JPY | |
|---|---|---|---|---|
| 0 | 174.908 | 22.6503 | A | 955.641 |
| 1 | 56.396 | 33.4669 | C | 301.729 |
| 2 | 111.685 | 10.779 | B | 814.984 |
| 3 | 81.1682 | 8.63424 | B | 708.732 |
| 4 | 115.511 | 36.7404 | A | 778.737 |
分析:
まず、最も基本的な「広さ」と「価格」の関係性を散布図で見てみましょう。
“`python
広さと価格の基本的な散布図
df_housing.plot.scatter(x=’Area_sqm’, y=’Price_JPY’, title=’Area vs Price (Basic Scatter Plot)’)
plt.xlabel(‘Area (sqm)’)
plt.ylabel(‘Price (JPY 10k)’)
plt.grid(True)
plt.show()
“`
読み取り: この基本的な散布図を見ると、データポイントがおおよそ右上がりの帯状に分布していることがわかります。これは、「住宅の広さが増加するにつれて、価格も上昇する傾向がある」という強い正の相関を示唆しています。点のばらつきも比較的少ないため、広さは価格を予測する上で重要な要素であると考えられます。
次に、「築年数」も価格に影響を与える変数と考えられます。広さと価格の関係性を、築年数の情報を加えて可視化してみましょう。築年数を点のサイズで表現します(築年数が古いほどサイズを大きくするなど、マッピング方法を検討)。ここでは、築年数が大きいほど点が大きくなるようにしてみましょう。
“`python
広さと価格の散布図に築年数をサイズで追加
点のサイズをAge_yearsで指定。サイズが大きすぎないように調整する
Pandasのs引数は「点の面積」に比例するため、値の平方根を使うと「点の半径」に比例し視覚的に分かりやすい場合がある
ただし、ここでは単純に Age_years をスケーリングして使用
size_scaled = df_housing[‘Age_years’] * 5 # 適当な倍率でサイズを調整
df_housing.plot.scatter(x=’Area_sqm’, y=’Price_JPY’, s=size_scaled, alpha=0.6, title=’Area vs Price, Point Size by Age’)
plt.xlabel(‘Area (sqm)’)
plt.ylabel(‘Price (JPY 10k)’)
サイズによる凡例はPandas plotでは自動でつかないため、必要に応じてMatplotlibやSeabornで手動追加
plt.show()
“`
読み取り: この図では、点の大きさで築年数を表しています。同じくらいの広さの住宅でも、築年数によって価格が異なる傾向があるかを目で追うことができます。例えば、図の右の方(広さが大きい)を見ると、比較的小さな点(築年数が若い)が高めの価格帯に位置し、大きな点(築年数が古い)がそれより低い価格帯に位置する傾向が見られるかもしれません。これにより、広さと価格の基本的な関係性に加えて、築年数という別の変数の影響も同時に考慮した分析が可能になります。
さらに、「地域」というカテゴリカルな変数も価格に影響を与える可能性があります。地域ごとに色分けして散布図を描くことで、地域ごとの広さと価格の関係性を比較してみましょう。ここではSeabornを使うと容易です。
“`python
広さと価格の散布図を地域で色分け (Seabornを使用)
plt.figure(figsize=(10, 7))
sns.scatterplot(data=df_housing, x=’Area_sqm’, y=’Price_JPY’, hue=’Region’, alpha=0.7)
plt.title(‘Area vs Price, Colored by Region’)
plt.xlabel(‘Area (sqm)’)
plt.ylabel(‘Price (JPY 10k)’)
plt.grid(True, linestyle=’–‘, alpha=0.6) # グリッド線もカスタマイズ
plt.show()
“`
読み取り: この散布図では、地域A、B、Cのデータポイントがそれぞれ異なる色で表示されています。凡例により、どの色がどの地域に対応するかがわかります。図を見ると、地域Aの点が全体的に価格が高く、地域Cの点が全体的に価格が低い傾向があることが一目でわかります。地域Bはその中間に位置しています。また、地域ごとに広さと価格の相関の強さや傾きが異なるかどうかも視覚的に比較できます。この例では、どの地域でも広さと価格の間に正の相関があるように見えますが、地域Aは同じ広さでも価格帯が一段高いことが明確です。
まとめ(例1): 住宅価格データに対する散布図を用いた分析から、以下の洞察が得られました。
* 住宅の「広さ」は「価格」と強い正の相関がある。
* 「築年数」が古いほど価格が低い傾向が見られる(サイズで表現した図から)。
* 「地域」によって価格水準が大きく異なる(色分けした図から)。特に地域Aは高価、地域Cは安価である。
これらの洞察は、住宅価格予測モデルを構築する際の特徴量エンジニアリングや、不動産市場のセグメンテーション分析において非常に役立ちます。散布図による初期的な可視化が、どの変数が重要で、どのような関係性にあるかを理解するための第一歩となります。
例2: 顧客データ分析 – 年齢と購入金額の関係性
シナリオ: オンラインストアの顧客データがあります。顧客の年齢と年間購入金額の間にどのような関係があるか、また、顧客の利用頻度や顧客タイプ(新規/リピーター)によって購入金額の傾向が異なるかを知りたいです。散布図を使って顧客セグメンテーションやマーケティング戦略のヒントを得るための分析を行います。
使用するデータ: 架空の顧客データ。「年齢(歳)」「年間購入金額(円)」「利用頻度(回/月)」「顧客タイプ(’New’, ‘Repeater’)」を持ちます。
データ作成:
“`python
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
np.random.seed(43)
n_customers = 300
age = np.random.rand(n_customers) * 60 + 20 # 年齢: 20~80歳
利用頻度は年齢と購入金額に関係があると仮定
frequency = np.random.rand(n_customers) * 10 + 1 # 利用頻度: 1~11 回/月
購入金額は年齢、利用頻度、顧客タイプに影響されると仮定
purchase_amount = age * 500 + frequency * 3000 + np.random.randn(n_customers) * 50000 # 基本モデル
リピーターは購入金額が高めと仮定
customer_type = np.random.choice([‘New’, ‘Repeater’], n_customers, p=[0.3, 0.7])
purchase_amount[customer_type == ‘Repeater’] *= (1 + np.random.rand(len(purchase_amount[customer_type == ‘Repeater’])) * 0.5) # リピーターは0%~50%増し
df_customer = pd.DataFrame({
‘Age’: age,
‘Monthly_Frequency’: frequency,
‘Customer_Type’: customer_type,
‘Annual_Purchase_Amount_JPY’: purchase_amount
})
購入金額に一部外れ値を挿入 (例: 高額購入者)
outlier_indices = np.random.choice(n_customers, 5, replace=False)
df_customer.loc[outlier_indices, ‘Annual_Purchase_Amount_JPY’] += np.random.rand(5) * 1000000
print(df_customer.head())
“`
| Age | Monthly_Frequency | Customer_Type | Annual_Purchase_Amount_JPY | |
|---|---|---|---|---|
| 0 | 56.239 | 10.3083 | Repeater | 553247 |
| 1 | 64.773 | 6.06285 | Repeater | 473251 |
| 2 | 39.353 | 8.41519 | Repeater | 347885 |
| 3 | 51.7452 | 1.55424 | Repeater | 273045 |
| 4 | 64.0133 | 7.36224 | Repeater | 515142 |
分析:
まず、年齢と年間購入金額の基本的な関係性を散布図で確認します。
“`python
年齢と年間購入金額の基本的な散布図
df_customer.plot.scatter(x=’Age’, y=’Annual_Purchase_Amount_JPY’, title=’Age vs Annual Purchase Amount’)
plt.xlabel(‘Age (years)’)
plt.ylabel(‘Annual Purchase Amount (JPY)’)
plt.grid(True)
plt.show()
“`
読み取り: この散布図を見ると、おおよそ年齢が高いほど購入金額も高い傾向があるように見えますが、ばらつきがかなり大きいです。また、他のデータポイントからかけ離れて非常に高い購入金額を示している点がいくつか確認できます。これらは高額購入者である可能性のある外れ値候補です。
次に、利用頻度を点のサイズで表現し、年齢と購入金額の関係性に追加情報を持たせてみましょう。利用頻度が高いほど点が大きくなるようにします。
“`python
年齢と年間購入金額の散布図に利用頻度をサイズで追加
size_scaled_freq = df_customer[‘Monthly_Frequency’] * 30 # 適当な倍率でサイズ調整
df_customer.plot.scatter(x=’Age’, y=’Annual_Purchase_Amount_JPY’, s=size_scaled_freq, alpha=0.5, title=’Age vs Purchase Amount, Point Size by Frequency’)
plt.xlabel(‘Age (years)’)
plt.ylabel(‘Annual Purchase Amount (JPY)’)
plt.show()
“`
読み取り: 点の大きさが利用頻度を表しています。同じ年齢層や購入金額の範囲でも、利用頻度が高い顧客(大きな点)と低い顧客(小さな点)がいることがわかります。例えば、年齢が高く購入金額も高い顧客層の中には、利用頻度が非常に高いヘビーユーザー(大きな点)が多く含まれているかもしれません。一方、購入金額が低い顧客層は、年齢に関わらず利用頻度が低い顧客が多いかもしれません。この図は、年齢と購入金額だけでなく、利用頻度も考慮した顧客セグメンテーションの可能性を示唆しています。
最後に、顧客タイプ(新規/リピーター)で色分けして、年齢と購入金額の関係性を比較します。Seabornを使用します。
“`python
年齢と年間購入金額の散布図を顧客タイプで色分け (Seabornを使用)
plt.figure(figsize=(10, 7))
sns.scatterplot(data=df_customer, x=’Age’, y=’Annual_Purchase_Amount_JPY’, hue=’Customer_Type’, alpha=0.7)
plt.title(‘Age vs Purchase Amount, Colored by Customer Type’)
plt.xlabel(‘Age (years)’)
plt.ylabel(‘Annual Purchase Amount (JPY)’)
plt.grid(True, linestyle=’–‘, alpha=0.6)
plt.show()
“`
読み取り: この散布図では、新規顧客とリピーターが異なる色で表示されています。図を見ると、リピーターは新規顧客に比べて、全体的に購入金額が高い傾向が明確にわかります。特に高額購入者の多くがリピーターであることが確認できます。また、年齢と購入金額の正の相関は、リピーターのグループでより顕著に見られるかもしれません。新規顧客は年齢に関わらず比較的購入金額が低い傾向があるようです。
まとめ(例2): 顧客データに対する散布図を用いた分析から、以下の洞察が得られました。
* 年齢と年間購入金額の間には正の相関傾向が見られるが、ばらつきが大きい。
* 外れ値として高額購入者が存在する。
* 利用頻度が高い顧客は購入金額が高い傾向がある(サイズで表現した図から)。
* リピーターは新規顧客に比べて明らかに購入金額が高い(色分けした図から)。高額購入者のほとんどがリピーターである。
これらの洞察は、顧客セグメンテーション(例: 年齢別、利用頻度別、顧客タイプ別)を行う上で重要です。例えば、リピーターを維持するための施策や、新規顧客の利用頻度を高めてリピーターへ育成するための施策の検討に役立ちます。高額購入者である外れ値は、VIP顧客として特別な分析や対応が必要かもしれません。
例3: 製造業データ分析 – 温度と製品不良率の関係性
シナリオ: ある製造ラインにおいて、製造時の「温度」が製品の「不良率」に影響を与えている可能性があると考えられています。また、製造された「バッチサイズ」や「シフト」(昼/夜)も影響しているかを知りたいです。散布図を使って、製造プロセスの最適化や品質改善のためのヒントを探します。
使用するデータ: 架空の製造データ。「製造温度(℃)」「不良率(%)」「バッチサイズ(個)」「シフト(’Day’, ‘Night’)」を持ちます。
データ作成:
“`python
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
np.random.seed(44)
n_batches = 200
temperature = np.random.rand(n_batches) * 50 + 150 # 温度: 150~200 ℃
batch_size = np.random.rand(n_batches) * 1000 + 500 # バッチサイズ: 500~1500 個
shift = np.random.choice([‘Day’, ‘Night’], n_batches, p=[0.6, 0.4])
不良率は温度が最適範囲(約170-180℃)から離れるほど高く、バッチサイズが大きいほど僅かに高めと仮定
シフトによる差も考慮
defect_rate = (temperature – 175)**2 * 0.005 + batch_size * 0.0001 + np.random.randn(n_batches) * 0.5 + 1 # 不良率モデル
defect_rate[shift == ‘Night’] += np.random.rand(len(defect_rate[shift == ‘Night’])) * 1.5 # 夜勤は不良率高めと仮定
defect_rate = np.clip(defect_rate, 0, None) # 不良率は0%未満にならないようにクリップ
df_manufacturing = pd.DataFrame({
‘Temperature_C’: temperature,
‘Batch_Size’: batch_size,
‘Shift’: shift,
‘Defect_Rate_Percent’: defect_rate
})
print(df_manufacturing.head())
“`
| Temperature_C | Batch_Size | Shift | Defect_Rate_Percent | |
|---|---|---|---|---|
| 0 | 174.761 | 1187.79 | Day | 1.0218 |
| 1 | 198.036 | 951.98 | Day | 3.01507 |
| 2 | 160.634 | 973.153 | Night | 4.21269 |
| 3 | 183.026 | 1141.51 | Day | 1.34698 |
| 4 | 187.381 | 564.191 | Day | 1.8448 |
分析:
まず、製造温度と不良率の基本的な散布図を見てみましょう。
“`python
製造温度と不良率の基本的な散布図
df_manufacturing.plot.scatter(x=’Temperature_C’, y=’Defect_Rate_Percent’, title=’Temperature vs Defect Rate’)
plt.xlabel(‘Temperature (C)’)
plt.ylabel(‘Defect Rate (%)’)
plt.grid(True)
plt.show()
“`
読み取り: この散布図を見ると、データポイントがU字型、あるいは放物線状に分布しているように見えます。つまり、製造温度が低すぎても高すぎても不良率が高くなり、ある特定の温度範囲(この例では約170℃~180℃付近)で不良率が最も低くなる傾向があることが示唆されます。これは非線形な関係性であり、散布図はこのような関係性の発見にも有効です。
次に、バッチサイズを点のサイズで表現し、温度と不良率の関係性に追加情報を持たせてみましょう。バッチサイズが大きいほど点が大きくなるようにします。
“`python
製造温度と不良率の散布図にバッチサイズをサイズで追加
size_scaled_batch = df_manufacturing[‘Batch_Size’] * 0.01 # 適当な倍率でサイズ調整
df_manufacturing.plot.scatter(x=’Temperature_C’, y=’Defect_Rate_Percent’, s=size_scaled_batch, alpha=0.6, title=’Temperature vs Defect Rate, Point Size by Batch Size’)
plt.xlabel(‘Temperature (C)’)
plt.ylabel(‘Defect Rate (%)’)
plt.show()
“`
読み取り: 点の大きさがバッチサイズを表しています。同じ温度帯でも、バッチサイズによって不良率が異なる傾向があるかを目で追うことができます。図を見ると、不良率が高い温度帯(温度が低い側と高い側)では、バッチサイズが大きい点(大きな点)も小さい点(小さな点)も混在しているようです。不良率が低い最適な温度帯ではどうでしょうか。バッチサイズが不良率に与える影響は、この図からだけでは限定的かもしれません。より詳細な分析(例えば、バッチサイズと不良率だけの散布図、あるいは統計的検定など)が必要でしょう。
最後に、シフト(昼/夜)で色分けして、温度と不良率の関係性を比較します。Seabornを使用します。
“`python
製造温度と不良率の散布図をシフトで色分け (Seabornを使用)
plt.figure(figsize=(10, 7))
sns.scatterplot(data=df_manufacturing, x=’Temperature_C’, y=’Defect_Rate_Percent’, hue=’Shift’, alpha=0.7)
plt.title(‘Temperature vs Defect Rate, Colored by Shift’)
plt.xlabel(‘Temperature (C)’)
plt.ylabel(‘Defect Rate (%)’)
plt.grid(True, linestyle=’–‘, alpha=0.6)
plt.show()
“`
読み取り: 昼勤と夜勤のデータポイントが異なる色で表示されています。図を見ると、全体的に夜勤のデータポイント(オレンジ色)は昼勤のデータポイント(青色)よりも不良率が高い位置に分布している傾向が明確にわかります。これは、夜勤の製造において何らかの要因(例: 疲労、人員体制、設備の安定性など)により不良率が高くなっている可能性を示唆しています。不良率が最も低くなる最適な温度範囲は、昼勤と夜勤で大きな違いはなさそうですが、夜勤の方が全体的に不良率のベースラインが高いようです。
まとめ(例3): 製造業データに対する散布図を用いた分析から、以下の洞察が得られました。
* 製造温度と不良率の間にはU字型の非線形な関係性があり、最適な温度範囲が存在する。
* バッチサイズと不良率の明確な関係性は、この散布図からは捉えにくい。
* 夜勤は昼勤に比べて全体的に不良率が高い傾向がある。
これらの洞察は、製造プロセスの改善に直接結びつきます。例えば、製造温度を最適な範囲に維持するための制御システムの調整や、夜勤の不良率が高い原因の特定と対策(例: 夜勤のオペレーターへの追加研修、夜間の設備点検強化など)の必要性が示唆されます。
例4: 金融データ分析 – リスクとリターンの関係性
シナリオ: 複数の投資資産(例: 個別株、投資信託など)の過去のデータがあります。各資産の「リスク」(ここではボラティリティ、つまり価格変動の度合い)と「リターン」(ここでは平均収益率)の関係性を知りたいです。散布図を使って、リスク・リターンのバランスを視覚的に把握し、ポートフォリオ構築の参考情報とします。
使用するデータ: 架空の投資資産データ。「リスク(年率ボラティリティ %)」「リターン(年率平均収益率 %)」「資産カテゴリ(例: ‘Equity’, ‘Bond’, ‘Real Estate’)」を持ちます。
データ作成:
“`python
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
np.random.seed(45)
n_assets = 100
リスクは低リスク(債券)から高リスク(株式)まで分布
risk = np.random.rand(n_assets) * 25 + 5 # リスク: 5%~30%
リターンはリスクが高くなるほど高くなる傾向(リスク・リターンはトレードオフ)
return_val = risk * 0.8 + np.random.randn(n_assets) * 5 + 2 # リターンモデル
資産カテゴリによる分類
asset_category = np.random.choice([‘Equity’, ‘Bond’, ‘Real Estate’], n_assets, p=[0.5, 0.3, 0.2])
カテゴリによってリスク・リターンの分布を調整
return_val[asset_category == ‘Bond’] -= np.random.rand(len(return_val[asset_category == ‘Bond’])) * 5 # 債券はリターン低め
risk[asset_category == ‘Bond’] -= np.random.rand(len(risk[asset_category == ‘Bond’])) * 5 # 債券はリスク低め
return_val[asset_category == ‘Real Estate’] += np.random.rand(len(return_val[asset_category == ‘Real Estate’])) * 3 # 不動産はリターンやや高め
risk[asset_category == ‘Real Estate’] += np.random.rand(len(risk[asset_category == ‘Real Estate’])) * 3 # 不動産はリスクやや高め
df_finance = pd.DataFrame({
‘Risk_Percent’: risk,
‘Return_Percent’: return_val,
‘Asset_Category’: asset_category
})
リスク、リターンが負になる場合は0にクリップ (単純化のため)
df_finance[‘Risk_Percent’] = np.clip(df_finance[‘Risk_Percent’], 0, None)
df_finance[‘Return_Percent’] = np.clip(df_finance[‘Return_Percent’], 0, None)
print(df_finance.head())
“`
| Risk_Percent | Return_Percent | Asset_Category | |
|---|---|---|---|
| 0 | 26.0912 | 17.1048 | Equity |
| 1 | 17.1537 | 16.202 | Equity |
| 2 | 23.5422 | 20.7848 | Equity |
| 3 | 4.67471 | 5.2435 | Bond |
| 4 | 22.8989 | 21.091 | Equity |
分析:
資産のリスクとリターンの関係性を散布図で確認します。これは金融の世界では一般的に「リスク・リターン図」と呼ばれるものです。
“`python
リスクとリターンの散布図
df_finance.plot.scatter(x=’Risk_Percent’, y=’Return_Percent’, title=’Risk vs Return of Assets’)
plt.xlabel(‘Risk (Annual Volatility %)’)
plt.ylabel(‘Return (Annual Average %)’)
plt.grid(True)
plt.show()
“`
読み取り: この散布図を見ると、データポイントはおおよそ右上がりの傾向を示しています。これは、「リスクが高い資産ほど、期待されるリターンも高い」という金融の基本的な考え方であるリスク・リターンのトレードオフの関係性を視覚的に表しています。一般的に、安全な資産(リスクが低い)はリターンも低く、積極的に収益を狙う資産(リスクが高い)はリターンも高くなる傾向があります。図上の各点が個々の資産を表しており、どの資産がリスクに対してどの程度のリターンを提供してきたかを確認できます。効率的なポートフォリオを考える上では、同じリスク水準でより高いリターンを提供している資産(図の上の方にある点)や、同じリターン水準でよりリスクが低い資産(図の左の方にある点)に注目することが考えられます。
次に、資産カテゴリで色分けして散布図を描き、カテゴリごとのリスク・リターンの特徴を比較してみましょう。Seabornを使用します。
“`python
リスクとリターンの散布図を資産カテゴリで色分け (Seabornを使用)
plt.figure(figsize=(10, 7))
sns.scatterplot(data=df_finance, x=’Risk_Percent’, y=’Return_Percent’, hue=’Asset_Category’, alpha=0.7, s=100) # sで点のサイズを少し大きく
plt.title(‘Risk vs Return, Colored by Asset Category’)
plt.xlabel(‘Risk (Annual Volatility %)’)
plt.ylabel(‘Return (Annual Average %)’)
plt.grid(True, linestyle=’–‘, alpha=0.6)
plt.show()
“`
読み取り: この散布図では、資産カテゴリ(Equity, Bond, Real Estate)ごとに点が色分けされています。図を見ると、資産カテゴリによってリスク・リターンの分布が異なる傾向があることがわかります。
* Bond (債券): 青い点で示されており、比較的リスクが低く(X軸の左側)、リターンも低い(Y軸の下の方)領域に集まっている傾向が見られます。
* Equity (株式): オレンジ色の点で示されており、リスクもリターンも比較的高い領域に広く分布している傾向が見られます。
* Real Estate (不動産): 緑色の点で示されており、株式と債券の中間か、やや株式寄りのリスク・リターン特性を持つものが多いように見えます。
このように、資産カテゴリによってリスク・リターンのプロファイルが異なることが視覚的に確認できます。これは、ポートフォリオを組む際に、異なるリスク・リターン特性を持つ資産カテゴリを組み合わせることで、リスクを分散しながら目標リターンを目指す、という戦略を考える上で重要な情報となります。
まとめ(例4): 金融データに対する散布図を用いた分析から、以下の洞察が得られました。
* 資産全体として、リスクとリターンの間に正の相関関係(トレードオフ)が見られる。
* 資産カテゴリによってリスク・リターンのプロファイルが異なり、債券は低リスク・低リターン、株式は高リスク・高リターンの傾向がある。不動産はその中間に位置するものが多い。
これらの洞察は、投資戦略の策定、資産配分の決定、ポートフォリオのリスク管理を行う上で基本的な出発点となります。個々の資産点を散布図上で評価することで、リスクとリターンのバランスを考慮した投資判断を視覚的にサポートできます。
これらの活用例は、散布図が単に二つの変数の関係を見るだけでなく、サイズや色といった他の変数の情報を取り込むことで、より多角的な視点からデータ分析を進めることができる強力なツールであることを示しています。Pandasの.plot.scatter()やSeabornのscatterplotを使いこなすことで、データに隠された興味深いパターンや洞察を発見する可能性が広がります。
7. 散布図を読む上での注意点と落とし穴
散布図は直感的で強力なツールですが、誤った解釈を招く可能性もあります。散布図から正しい洞察を得るためには、いくつかの注意点を知っておく必要があります。
相関関係と因果関係の違い
散布図で二つの変数の間に強い相関が見られたとしても、それは直ちに一方の変数が他方の変数の原因であるという「因果関係」を意味しません。相関はあくまで「共に変動する傾向がある」という統計的な関係性を示すものであり、そこに因果関係があるかどうかは、ドメイン知識やさらに踏み込んだ統計分析(実験計画法、回帰分析での共変量の考慮など)によって判断する必要があります。
例えば、「アイスクリームの売上」と「水難事故の発生件数」の散布図を描くと、強い正の相関が見られるかもしれません。しかし、これはアイスクリームが水難事故の原因であるというわけではありません。これらの変数はいずれも「気温が高い」という第三の変数に影響を受けている可能性が高く、これは「擬似相関」と呼ばれます。
散布図で相関を見つけたら、「なぜそのような関係性が見られるのか?」と問い、隠れた共通の原因や媒介変数がないかを検討することが重要です。
データのスケールと軸の範囲設定
軸のスケール(線形か対数か)や表示範囲を適切に設定しないと、データの分布や関係性が歪んで見えたり、重要な情報が隠れてしまったりすることがあります。
- 広すぎる範囲: 軸の範囲をデータの最小値・最大値よりはるかに広く設定すると、データポイントが図の中心に小さく集まってしまい、詳細な分布やパターンが見えにくくなります。
- 狭すぎる範囲: 逆に、軸の範囲を狭く設定しすぎると、一部のデータにしか焦点を当てられず、全体像や外れ値を見落とす可能性があります。また、意図的に狭い範囲を設定することで、実際には弱い相関を強く見せかけるなどのミスリーディングな表現につながる可能性もあります。
- 対数スケールの誤用: 値の範囲が広いデータを対数スケールで表示するのは有効ですが、対数変換がデータの性質や分析目的に合っているかを確認する必要があります。例えば、負の値やゼロを含むデータには単純な対数変換は適用できません。また、対数スケールで線形に見えるからといって、元のスケールでも線形な関係があるわけではないことに注意が必要です。
常に、データの性質と分析の目的に合った軸のスケールと範囲を選択することが重要です。
多すぎるデータポイント(オーバープロット問題)
データポイントの数が非常に多い場合、点が密集して重なり合い、個々の点が見えにくくなるだけでなく、データの密度が高い領域と低い領域の区別がつきにくくなる「オーバープロット」が発生します(4. 透過性の設定の例を参照)。
オーバープロットの対策としては、以下のような方法があります。
- 透過性(alpha)の調整: 点を半透明にすることで、重なり合った部分の色の濃淡で密集度を表現できます。Pandasの
.plot.scatter()やSeabornのscatterplotでalpha引数を使用します。 - 点のサイズ(s)の縮小: 点のサイズを小さくすることで、重なる度合いを減らすことができます。
- マーカーの変更: デフォルトの円よりも小さい点(
marker='.')など、重なってもつぶれにくいマーカーを選択します。 - ビンニング(Binning): データを二次元のグリッドに区切り、各グリッド内のデータポイント数を数えてヒートマップのように表示する(2Dヒストグラムなど)。Pandasの
.plotメソッドにはhexbinやkde(カーネル密度推定)といった関連するプロットタイプがあります。 - データのサンプリング: データが非常に多い場合は、ランダムに一部のデータをサンプリングしてプロットする。ただし、サンプリングによってレアなパターンや外れ値を見落とす可能性があるため注意が必要です。
データの量と特性に応じて、最適なオーバープロット対策を選択することが重要です。
外れ値の影響
散布図は外れ値を視覚的に特定するのに役立ちますが、同時に、外れ値が軸の範囲やスケールに影響を与え、他の多くのデータポイントの分布を見えにくくすることがあります。また、外れ値は相関係数や回帰分析の結果を大きく歪める可能性があります。
散布図で外れ値を見つけたら、その点が本当にデータエラーなのか、それとも分析上重要な意味を持つ例外的な観測値なのかを調査することが重要です。外れ値をどのように扱うか(除外、修正、別途分析など)は、分析の目的や外れ値の原因によって慎重に判断する必要があります。外れ値を表示した散布図と、外れ値を除外した散布図の両方を作成して比較することも有効です。
適切な変数の選択
散布図は常に二つの数値変数間の関係性をプロットします。分析したい関係性を適切に捉えるためには、どの変数をX軸、Y軸に配置するかを適切に選択する必要があります。例えば、「原因かもしれない変数」をX軸に、「結果かもしれない変数」をY軸に配置するのが一般的ですが、これは必須ではありません。また、カテゴリ変数や順序変数など、散布図の軸には直接適さない変数については、前処理で数値に変換したり、色やサイズ、マーカーといった他の視覚要素にマッピングしたりする工夫が必要になります。
その他の注意点
- 軸ラベルとタイトルの明確さ: グラフのタイトル、X軸ラベル、Y軸ラベルは、それぞれが何を表しているのか、単位は何かなどを明確に記述し、グラフを見た人がすぐに内容を理解できるようにすることが重要です。
- 凡例の利用: 色やサイズ、マーカーなどで複数の情報を表現した場合は、凡例を必ず表示し、どの要素が何を示しているかを明確に伝える必要があります。Seabornはこの点で優れています。
- 文脈の考慮: 散布図から読み取れるパターンや関係性は、そのデータが取得された背景や文脈(例: 業界、時期、対象者など)の中で解釈される必要があります。統計的な関係性だけを見て、文脈を無視した結論を出すのは危険です。
これらの注意点を踏まえることで、散布図をより正確に読み解き、データ分析から信頼性の高い洞察を得ることができます。
8. まとめ:学びの振り返りと次のステップ
この記事では、Pandasを使った散布図の基本的な描画方法から、点のサイズや色、透過性といった応用的なカスタマイズ、そして実際のデータ分析における活用例までを詳細に解説しました。
重要なポイントの振り返り:
- 散布図は二つの数値変数間の関係性(相関、分布、外れ値など)を視覚的に捉えるための強力なツールであり、探索的データ分析において中心的な役割を果たします。
- Pandas DataFrameは、
.plot.scatter()メソッドを通じて散布図描画機能を提供しており、DataFrameから直接、手軽に散布図を作成できます。 - Pandasの
.plot()メソッドは内部的にMatplotlibを使用しているため、描画後にMatplotlibの機能を使ってタイトル、軸ラベル、グリッド線などのカスタマイズが可能です。 s引数で点のサイズ、c引数で点の色のグラデーション、alpha引数で透過性、marker引数でマーカー形状をカスタマイズすることで、3つ目、4つ目の変数情報を散布図に組み込むことができ、より多くの洞察を得られます。ax引数を利用することで、複数の散布図を同一グラフ上に重ねて描画し、異なるデータ系列や関係性を比較できます。- 値の範囲が広いデータに対しては、
logxやlogy引数で対数スケールを適用することが有効な場合があります。 - Seabornのような他の可視化ライブラリは、特にカテゴリ変数による色分けや統計的な要素(回帰直線など)の追加を、Pandasよりも直感的かつ容易に行うことができます。PandasとSeabornはそれぞれ強みがあり、分析の目的やデータの性質に応じて使い分ける、あるいは組み合わせることが推奨されます。
- 住宅価格、顧客、製造業、金融など、様々な分野のデータ分析において、散布図は変数間の関係性を理解し、外れ値を発見し、さらなる分析の方向性を見出すための第一歩として広く活用されています。
- 散布図を解釈する際には、相関と因果の違い、データのスケール、オーバープロット、外れ値の影響といった注意点を考慮することが非常に重要です。
次のステップ:
この記事で紹介した内容は、Pandasを使った散布図描画の基本的な部分とその応用です。さらにスキルを深めるためには、以下のステップが考えられます。
- 様々なデータセットでの実践: 実際に様々な種類の公開データセット(Kaggleなど)を使って、学んだ散布図の描画方法を実践してみましょう。実際のデータは理想的な分布をしているとは限らず、前処理が必要になることも多いです。
- Matplotlibによる詳細なカスタマイズ: Pandasの
.plot()が返すMatplotlib Axesオブジェクトを操作して、凡例の細かな調整、テキストアノテーションの追加、複数のプロット領域(サブプロット)を持つ図の作成など、より高度なカスタマイズ方法を習得しましょう。 - Seabornの活用: Seabornの
scatterplot以外の関数(regplot,lmplot,pairplotなど)も積極的に使ってみましょう。カテゴリ変数の多いデータや、複数の変数間の関係性を網羅的に見たい場合に特に有効です。 - 他の可視化ライブラリ: BokehやPlotlyなど、インタラクティブなグラフを作成できるライブラリについても学んでみましょう。これらのライブラリもPandas DataFrameとの連携が可能です。インタラクティブな散布図は、データポイントの詳細情報をツールチップで表示したり、特定の範囲をズームしたりするのに便利です。
- 統計学との連携: 散布図で見つけた相関関係を、相関係数の計算や線形回帰分析といった統計的手法で定量的に評価する方法を学びましょう。可視化で得た示唆を統計的に検証することが、データ分析の信頼性を高めます。
データ可視化は、データ分析のプロセスにおいて、データそのものから洞察を引き出し、発見したパターンを他者に伝えるための最も重要な手段の一つです。Pandasと散布図を効果的に使いこなすことで、あなたのデータ分析スキルは飛躍的に向上するでしょう。
この記事が、あなたのデータ分析・可視化の旅の役に立てば幸いです。