Pythonデータ分析入門 - Pandasから可視化まで
Python Data Analysis Beginner Guide - From Pandas to Visualization
はじめに:データ分析が重要な理由とPythonが最適な理由
私たちは毎日膨大な量のデータが生成される時代に生きています。企業の売上データ、ソーシャルメディアのユーザー行動ログ、政府の公共統計資料まで、これらすべてのデータの中には意味のあるパターンとインサイトが隠されています。データ分析とは、このような生のデータを体系的に整理・分析し、意思決定に役立つ情報を抽出するプロセスです。マーケティング戦略の策定、製品改善、リスク予測など、データ分析は今やほぼすべての産業分野でコア・コンピタンスとなっています。
では、なぜ数あるプログラミング言語の中でPythonがデータ分析の代表的な言語として定着したのでしょうか?第一に、Pythonは文法が直感的で読みやすく、プログラミング初心者でもすぐに学習できます。第二に、Pandas、NumPy、Matplotlib、Seabornなど、データ分析に特化した強力なライブラリエコシステムを備えています。第三に、Jupyter Notebookという対話型開発環境を通じて、コードの実行結果をすぐに確認しながら分析作業を進めることができます。第四に、世界最大の開発者コミュニティを有しており、問題解決に必要な資料を簡単に見つけることができます。
この記事では、Pythonデータ分析の基礎を環境設定から実践プロジェクトまでステップバイステップでガイドします。プログラミング経験のない完全な初心者でも、このガイドに沿って進めれば基本的なデータ分析ができるようになるでしょう。
1. 環境設定:分析のための第一歩
1.1 Pythonのインストール
データ分析を始めるには、まずPythonをインストールする必要があります。2026年現在、Python 3.12以上のバージョンを推奨します。公式ウェブサイト(python.org)からOSに合ったインストーラーをダウンロードできます。インストール時に必ず「Add Python to PATH」オプションにチェックを入れてください。そうすることで、ターミナルからすぐにPythonを実行できます。
インストールが完了したら、ターミナル(コマンドプロンプト)でバージョンを確認します。
# Pythonバージョン確認
python --version
# 出力例: Python 3.12.x
# pipバージョン確認
pip --version
1.2 Anacondaを活用したオールインワンインストール
データ分析に必要なライブラリを個別にインストールするのが面倒な場合は、Anacondaディストリビューションをおすすめします。Anacondaは、Pythonと共にPandas、NumPy、Matplotlib、Jupyter Notebookなど、データサイエンスに必要な主要パッケージを一度にインストールしてくれます。
# Anacondaインストール後に仮想環境を作成
conda create -n data_analysis python=3.12
conda activate data_analysis
# 必要なパッケージはすでに含まれていますが、追加インストールが必要な場合
conda install pandas numpy matplotlib seaborn jupyter
1.3 Jupyter Notebookを始めよう
Jupyter Notebookはデータアナリストにとって必須のツールです。コードをセル単位で実行し、結果をすぐに確認できるため、探索的データ分析(EDA)に非常に適しています。マークダウンセルを活用すれば、分析過程の説明も一緒に記録できます。
# pipでインストールする場合
pip install jupyter notebook
# Jupyter Notebookを起動
jupyter notebook
# またはJupyterLab(次世代バージョン)を起動
pip install jupyterlab
jupyter lab
ブラウザが自動的に開き、Jupyterダッシュボードが表示されます。右上の「New > Python 3」をクリックすると、新しいノートブックが作成されます。
2. Pandasの基礎:データ分析のコアライブラリ
2.1 DataFrameとSeriesを理解する
PandasはPythonデータ分析のコアライブラリです。Pandasの2つの主要なデータ構造であるSeriesとDataFrameを理解することが最初のステップです。Seriesは1次元配列(1つの列)であり、DataFrameは行と列で構成される2次元テーブル(Excelシートに類似)です。
import pandas as pd
import numpy as np
# Seriesの作成
s = pd.Series([10, 20, 30, 40, 50],
index=['a', 'b', 'c', 'd', 'e'])
print(s)
# 出力:
# a 10
# b 20
# c 30
# d 40
# e 50
# dtype: int64
# DataFrameの作成
data = {
'名前': ['田中', '鈴木', '佐藤', '高橋', '伊藤'],
'年齢': [25, 30, 28, 35, 22],
'都市': ['東京', '大阪', '名古屋', '東京', '横浜'],
'スコア': [85, 92, 78, 95, 88]
}
df = pd.DataFrame(data)
print(df)
# 出力:
# 名前 年齢 都市 スコア
# 0 田中 25 東京 85
# 1 鈴木 30 大阪 92
# 2 佐藤 28 名古屋 78
# 3 高橋 35 東京 95
# 4 伊藤 22 横浜 88
2.2 データの読み込みと書き出し
実際のデータ分析では、CSV、Excel、JSONなどさまざまな形式のファイルを読み込む必要があります。Pandasはそのための便利な関数を提供しています。
# CSVファイルの読み込み
df_csv = pd.read_csv('data.csv', encoding='utf-8')
# Excelファイルの読み込み
df_excel = pd.read_excel('data.xlsx', sheet_name='Sheet1')
# JSONファイルの読み込み
df_json = pd.read_json('data.json')
# WebのURLから直接読み込み
url = 'https://example.com/data.csv'
df_web = pd.read_csv(url)
# DataFrameの基本情報を確認
print(df_csv.shape) # (行数, 列数)
print(df_csv.info()) # 列名、型、欠損値情報
print(df_csv.describe()) # 数値列の統計要約
print(df_csv.head(10)) # 上位10行を表示
# ファイルに保存
df_csv.to_csv('output.csv', index=False, encoding='utf-8-sig')
df_csv.to_excel('output.xlsx', index=False)
2.3 インデキシングとフィルタリング
データから必要な部分だけを選択・抽出することは、データ分析の最も基本的な作業です。Pandasはさまざまなインデキシング方法を提供しています。
# 列の選択
print(df['名前']) # 単一列(Seriesを返す)
print(df[['名前', 'スコア']]) # 複数列(DataFrameを返す)
# 行の選択 - loc(ラベルベース)
print(df.loc[0]) # インデックス0の行
print(df.loc[0:2]) # インデックス0〜2の行(終端含む)
# 行の選択 - iloc(整数位置ベース)
print(df.iloc[0]) # 最初の行
print(df.iloc[0:2]) # 1行目〜2行目(終端含まず)
# 条件フィルタリング
print(df[df['年齢'] >= 28]) # 28歳以上
print(df[df['都市'] == '東京']) # 東京在住者
print(df[(df['年齢'] >= 25) & (df['スコア'] >= 90)]) # 複合条件
# 特定の値を含むかどうかでフィルタリング
cities = ['東京', '大阪']
print(df[df['都市'].isin(cities)])
# 文字列を含むかどうかでフィルタリング
print(df[df['名前'].str.contains('田')])
3. データ前処理:分析品質を左右する重要なステップ
現実のデータは完璧ではありません。欠損値(空白値)、重複データ、不正な形式などさまざまな問題が存在します。データ前処理とは、これらの問題を解決し、分析に適した形にデータを整理するプロセスです。実際のデータ分析業務では、前処理が全作業時間の60〜80%を占めると言われているほど重要な段階です。
3.1 欠損値(Missing Value)の処理
# 欠損値を含むサンプルデータの作成
data = {
'名前': ['田中', '鈴木', None, '高橋', '伊藤'],
'年齢': [25, np.nan, 28, 35, 22],
'都市': ['東京', '大阪', '名古屋', None, '横浜'],
'スコア': [85, 92, np.nan, 95, 88]
}
df = pd.DataFrame(data)
# 欠損値の確認
print(df.isnull().sum()) # 各列の欠損値数
print(df.isnull().sum().sum()) # 全体の欠損値数
# 欠損値の削除
df_dropped = df.dropna() # 欠損値がある行をすべて削除
df_dropped_col = df.dropna(axis=1) # 欠損値がある列をすべて削除
df_thresh = df.dropna(thresh=3) # 非欠損値が3個以上の行のみ保持
# 欠損値の補完
df['年齢'] = df['年齢'].fillna(df['年齢'].mean()) # 平均値で補完
df['都市'] = df['都市'].fillna('不明') # 特定の値で補完
df['スコア'] = df['スコア'].fillna(method='ffill') # 前の値で補完
df['名前'] = df['名前'].fillna('不明') # 文字列で補完
3.2 重複データの削除
# 重複行の確認
print(df.duplicated().sum()) # 全体の重複行数
print(df.duplicated(subset=['名前'])) # 特定列基準の重複確認
# 重複の削除
df_unique = df.drop_duplicates() # 全列基準
df_unique_name = df.drop_duplicates(subset=['名前']) # '名前'列基準
df_unique_last = df.drop_duplicates(
subset=['名前'], keep='last' # 最後の値を保持
)
3.3 データ型の変換
# 現在のデータ型を確認
print(df.dtypes)
# 型変換
df['年齢'] = df['年齢'].astype(int) # 整数型に変換
df['スコア'] = df['スコア'].astype(float) # 浮動小数点型に変換
df['名前'] = df['名前'].astype(str) # 文字列型に変換
# 日付型への変換
df['日付'] = pd.to_datetime(df['日付文字列'], format='%Y-%m-%d')
# カテゴリ型への変換(メモリ節約に効果的)
df['都市'] = df['都市'].astype('category')
3.4 グループ化と集計
データを特定の基準でグループ化し集計することは、データから意味のあるパターンを発見するための核心的な手法です。
# 都市別の平均スコア
print(df.groupby('都市')['スコア'].mean())
# 都市別の複数の統計量を一度に計算
print(df.groupby('都市')['スコア'].agg(['mean', 'max', 'min', 'count']))
# 複数列基準でグループ化
print(df.groupby(['都市', '性別'])['スコア'].mean())
# ピボットテーブル(Excelのピボットテーブルと同様)
pivot = df.pivot_table(
values='スコア',
index='都市',
columns='性別',
aggfunc='mean',
fill_value=0
)
print(pivot)
4. データの可視化:MatplotlibとSeaborn
数値だけではデータのパターンやトレンドを直感的に把握するのは困難です。可視化はデータをグラフやチャートで表現し、複雑な情報を一目で理解できるようにします。PythonではMatplotlib(基本的な可視化)とSeaborn(統計的な可視化)が最も広く使用されています。
4.1 Matplotlibの基礎
import matplotlib.pyplot as plt
# 日本語フォント設定(Windows基準)
plt.rcParams['font.family'] = 'Meiryo'
plt.rcParams['axes.unicode_minus'] = False # マイナス記号の文字化け防止
# 1. 折れ線グラフ(Line Plot)- 時間経過に伴う変化の追跡に適切
months = ['1月', '2月', '3月', '4月', '5月', '6月']
sales = [150, 180, 200, 170, 220, 250]
plt.figure(figsize=(10, 6))
plt.plot(months, sales, marker='o', linewidth=2, color='#3498db')
plt.title('月別売上推移', fontsize=16, fontweight='bold')
plt.xlabel('月', fontsize=12)
plt.ylabel('売上(万円)', fontsize=12)
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig('line_chart.png', dpi=150)
plt.show()
# 2. 棒グラフ(Bar Chart)- カテゴリ別比較に適切
categories = ['電子機器', '衣類', '食品', '家具', '書籍']
values = [450, 320, 280, 190, 150]
plt.figure(figsize=(10, 6))
bars = plt.bar(categories, values, color=['#3498db', '#2ecc71', '#e74c3c',
'#f39c12', '#9b59b6'])
plt.title('カテゴリ別販売数', fontsize=16, fontweight='bold')
plt.xlabel('カテゴリ', fontsize=12)
plt.ylabel('販売数', fontsize=12)
# 各棒の上に値を表示
for bar, val in zip(bars, values):
plt.text(bar.get_x() + bar.get_width()/2., bar.get_height() + 5,
str(val), ha='center', va='bottom', fontsize=11)
plt.tight_layout()
plt.show()
# 3. 円グラフ(Pie Chart)- 割合の表示に適切
labels = ['東京', '神奈川', '大阪', '愛知', 'その他']
sizes = [35, 25, 15, 10, 15]
colors = ['#3498db', '#2ecc71', '#e74c3c', '#f39c12', '#9b59b6']
explode = (0.05, 0, 0, 0, 0) # 東京のスライスを少し分離
plt.figure(figsize=(8, 8))
plt.pie(sizes, explode=explode, labels=labels, colors=colors,
autopct='%1.1f%%', shadow=True, startangle=90)
plt.title('地域別ユーザー分布', fontsize=16, fontweight='bold')
plt.tight_layout()
plt.show()
4.2 Seabornによる高度な可視化
SeabornはMatplotlibをベースにしながら、より美しく統計的に意味のあるグラフをシンプルなコードで生成できるライブラリです。
import seaborn as sns
# Seabornのデフォルトテーマ設定
sns.set_theme(style='whitegrid', font='Meiryo')
# サンプルデータの作成
np.random.seed(42)
df_sample = pd.DataFrame({
'部署': np.random.choice(['開発部', 'マーケティング部', '営業部', 'デザイン部'], 200),
'経験年数': np.random.randint(1, 15, 200),
'年収(万円)': np.random.normal(5000, 1500, 200).astype(int),
'満足度': np.random.uniform(1, 5, 200).round(1)
})
# 1. ヒストグラム - データ分布の確認
plt.figure(figsize=(10, 6))
sns.histplot(data=df_sample, x='年収(万円)', bins=20, kde=True, color='#3498db')
plt.title('年収分布', fontsize=16, fontweight='bold')
plt.tight_layout()
plt.show()
# 2. ボックスプロット - 部署別年収分布の比較
plt.figure(figsize=(10, 6))
sns.boxplot(data=df_sample, x='部署', y='年収(万円)', palette='Set2')
plt.title('部署別年収分布', fontsize=16, fontweight='bold')
plt.tight_layout()
plt.show()
# 3. 散布図 - 経験年数と年収の関係
plt.figure(figsize=(10, 6))
sns.scatterplot(data=df_sample, x='経験年数', y='年収(万円)',
hue='部署', style='部署', s=80, alpha=0.7)
plt.title('経験年数 vs 年収(部署別)', fontsize=16, fontweight='bold')
plt.tight_layout()
plt.show()
# 4. ヒートマップ - 相関関係の可視化
plt.figure(figsize=(8, 6))
numeric_cols = df_sample.select_dtypes(include=[np.number])
sns.heatmap(numeric_cols.corr(), annot=True, cmap='coolwarm',
center=0, fmt='.2f', linewidths=0.5)
plt.title('変数間の相関関係', fontsize=16, fontweight='bold')
plt.tight_layout()
plt.show()
5. 実践プロジェクト:公開データで学ぶデータ分析
ここまで学んだ内容を総合して、実際の公開データを分析するミニプロジェクトを実施しましょう。この例ではソウル市の区別人口統計の架空データを使用します。実際の公開データは韓国公共データポータル(data.go.kr)やソウルオープンデータ広場(data.seoul.go.kr)からダウンロードできます。
5.1 データの準備と探索
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
# 日本語フォント設定
plt.rcParams['font.family'] = 'Meiryo'
plt.rcParams['axes.unicode_minus'] = False
sns.set_theme(style='whitegrid', font='Meiryo')
# ソウル市区別人口データの作成(架空データ)
data = {
'区': ['江南区', '江東区', '江北区', '江西区', '冠岳区',
'広津区', '九老区', '衿川区', '蘆原区', '道峰区',
'東大門区', '銅雀区', '麻浦区', '西大門区', '瑞草区',
'城東区', '城北区', '松坡区', '陽川区', '永登浦区',
'龍山区', '恩平区', '鍾路区', '中区', '中浪区'],
'人口': [527641, 426067, 303065, 577586, 497702,
356174, 411084, 230696, 518922, 324686,
347780, 392163, 378476, 314109, 429154,
311024, 436592, 667483, 457806, 397789,
229431, 481623, 149479, 125177, 398690],
'世帯数': [231547, 183224, 143628, 258921, 247896,
161438, 189362, 115892, 214567, 137852,
168234, 177621, 184523, 148762, 185423,
145234, 193458, 278456, 186742, 189234,
113256, 201234, 75623, 65892, 172345],
'面積': [39.50, 24.59, 23.60, 41.44, 29.57,
17.06, 20.12, 13.01, 35.44, 20.70,
14.22, 16.35, 23.84, 17.61, 46.98,
16.85, 24.57, 33.87, 17.41, 24.55,
21.87, 29.71, 23.91, 9.96, 18.50],
'高齢者比率': [12.8, 14.2, 19.5, 13.6, 14.8,
13.1, 15.3, 13.9, 16.2, 18.7,
16.8, 14.1, 12.4, 16.1, 11.9,
13.5, 17.2, 11.8, 14.5, 14.9,
15.2, 16.4, 18.1, 17.5, 16.9]
}
df = pd.DataFrame(data)
# 基本的な探索
print("=== データの基本情報 ===")
print(f"データサイズ: {df.shape}")
print(f"\nデータ型:\n{df.dtypes}")
print(f"\n基本統計量:\n{df.describe()}")
print(f"\n上位5行:\n{df.head()}")
5.2 派生変数の作成と分析
# 人口密度の計算(人口 / 面積)
df['人口密度'] = (df['人口'] / df['面積']).round(0).astype(int)
# 世帯当たりの人口を計算
df['世帯当たり人口'] = (df['人口'] / df['世帯数']).round(2)
# 人口上位5区
top5_pop = df.nlargest(5, '人口')
print("=== 人口上位5区 ===")
print(top5_pop[['区', '人口', '人口密度']])
# 人口密度上位5区
top5_density = df.nlargest(5, '人口密度')
print("\n=== 人口密度上位5区 ===")
print(top5_density[['区', '人口密度', '面積']])
# 高齢者比率による分類
df['高齢化段階'] = pd.cut(df['高齢者比率'],
bins=[0, 7, 14, 20, 100],
labels=['高齢化社会未満', '高齢化社会',
'高齢社会', '超高齢社会'])
print("\n=== 高齢化段階別の区の数 ===")
print(df['高齢化段階'].value_counts())
5.3 総合的な可視化
# 4つのチャートを1つのFigureに配置
fig, axes = plt.subplots(2, 2, figsize=(16, 12))
fig.suptitle('ソウル市区別人口分析ダッシュボード', fontsize=20, fontweight='bold', y=1.02)
# 1) 人口上位10区 - 横棒グラフ
top10 = df.nlargest(10, '人口')
axes[0, 0].barh(top10['区'], top10['人口'], color='#3498db')
axes[0, 0].set_title('人口上位10区', fontsize=14, fontweight='bold')
axes[0, 0].set_xlabel('人口')
axes[0, 0].invert_yaxis()
# 2) 人口密度の分布 - ヒストグラム
axes[0, 1].hist(df['人口密度'], bins=10, color='#2ecc71', edgecolor='white')
axes[0, 1].set_title('人口密度の分布', fontsize=14, fontweight='bold')
axes[0, 1].set_xlabel('人口密度(人/km2)')
axes[0, 1].set_ylabel('区の数')
axes[0, 1].axvline(df['人口密度'].mean(), color='red', linestyle='--',
label=f'平均: {df["人口密度"].mean():.0f}')
axes[0, 1].legend()
# 3) 面積 vs 人口の散布図
scatter = axes[1, 0].scatter(df['面積'], df['人口'],
c=df['高齢者比率'], cmap='RdYlGn_r',
s=100, alpha=0.7, edgecolors='gray')
axes[1, 0].set_title('面積 vs 人口(色:高齢者比率)', fontsize=14, fontweight='bold')
axes[1, 0].set_xlabel('面積(km2)')
axes[1, 0].set_ylabel('人口')
plt.colorbar(scatter, ax=axes[1, 0], label='高齢者比率(%)')
# 4) 高齢化段階別の分布 - 円グラフ
stage_counts = df['高齢化段階'].value_counts()
axes[1, 1].pie(stage_counts.values, labels=stage_counts.index,
autopct='%1.1f%%', colors=['#2ecc71', '#f39c12', '#e74c3c'],
startangle=90, shadow=True)
axes[1, 1].set_title('高齢化段階別の区の分布', fontsize=14, fontweight='bold')
plt.tight_layout()
plt.savefig('seoul_population_dashboard.png', dpi=150, bbox_inches='tight')
plt.show()
print("\n分析完了!'seoul_population_dashboard.png'ファイルが保存されました。")
TIP: 公共データポータル(data.go.kr)から実際のデータをダウンロードして、上記コードの架空データの代わりに使用してみてください。CSV形式で提供されるデータが多いため、
pd.read_csv()で直接読み込むことができます。
まとめ:次のステップへの学習ロードマップ
この記事で扱った内容はPythonデータ分析の基礎に該当します。環境設定からPandasを活用したデータ操作、前処理、そしてMatplotlibとSeabornを活用した可視化まで、データ分析の全体的なワークフローを体験しました。実践プロジェクトを通じて、これらすべてのプロセスがどのように連携するかも確認できました。
ここで止まらず、次のステップに進むための学習ロードマップを提案します。第一に、NumPyを深く学習してください。Pandasの内部でNumPyが動作しているため、配列演算とベクトル化の概念を理解すれば、はるかに効率的なコードを書くことができます。第二に、Scikit-learnライブラリを通じて機械学習の基礎を身につけてください。回帰分析、分類、クラスタリングなどの基本アルゴリズムをデータに適用すれば、予測とパターン発見の領域に拡張できます。第三に、SQLの基礎も併せて学習してください。実務ではデータのほとんどがデータベースに保存されているため、SQLでデータを抽出しPandasで分析するワークフローが非常に一般的です。
さらに、PlotlyやBokehのようなインタラクティブ可視化ライブラリ、StreamlitやDashを活用したデータダッシュボードの構築、そしてApache SparkのPySparkを活用した大規模データ処理まで学習範囲を広げていけば、データアナリストまたはデータサイエンティストとしての能力を体系的に身につけることができます。最も重要なのは継続的な実践です。公共データポータル、Kaggleなどで興味のあるデータセットを見つけて、実際に分析プロジェクトを行ってみてください。理論だけでは体得できない実践的な感覚を身につけることができるでしょう。データ分析の世界は広大で、皆さんの旅はまだ始まったばかりです。