メインコンテンツにスキップ

Python pandasチュートリアル:初心者のための完全ガイド

インストールから分析まで、すべての例をpandas 3.1で検証済み。
· 15 分 読む

AIで探求

pandasはPythonの標準的なデータ分析パッケージで、PyPIでは月5億回以上ダウンロードされています。CSV、Excel、JSON、SQLなど多様な形式を読み書きでき、表形式データの日常的な整形、変換、集計、可視化の作業を幅広くカバーします。

このpandasチュートリアルでは、1つの実データセットを使ってワークフロー全体を通して解説します。pandasのインストール、データのインポートとエクスポート、DataFrameの確認、行の選択とフィルタリング、欠損値や重複のクリーニング、テーブルの結合、集計、プロットまで扱います。すべての例は現行リリースであるpandas 3.1で動作し、古いチュートリアルのコードを壊すpandas 3の変更点にも注意を促します。

必要なのはPythonの基礎だけで、pandasの事前経験は不要です。より長期的な学習計画は、pandasの学び方の記事を、対話的な練習はData Manipulation with pandasコースをご覧ください。

要点

  • pandasはDataFrameで表形式データを扱う、Pythonの標準ライブラリです。
  • pip install pandasでインストールします。pandas 3はPython 3.11以降が必要です。
  • 基本ワークフローは、読み込み、確認、選択、クリーンアップ、結合、集計、プロット、エクスポートです。
  • .loc[]はラベル指定、.iloc[]は位置指定で選択します。
  • pandas 3以降、連鎖代入はデータを更新しません。1回の.loc[]呼び出しで更新してください。
  • 非推奨のinplace=Trueではなく、結果を再代入します(例:df = df.dropna())。

pandasとは?

pandasはPythonで表形式データを扱うためのデータ操作パッケージです。つまり、行と列からなるデータ(DataFrame)を対象にします。直感的には、DataFrameはExcelシートのようなものと考えられます。

pandasの機能には、行の並べ替えや部分抽出といった変換から、平均などの要約統計の計算、DataFrameの形状変更、DataFrame同士の結合まで含まれます。いわゆるPyDataエコシステムの他の人気Pythonライブラリとも相性が良く、次のようなものがあります。

pandasは何に使う?

pandasはデータ分析のワークフロー全体で使われます。例えば、次のことが可能です。

  • データベース、スプレッドシート、CSVなどからデータセットをインポートする。
  • 欠損値への対処など、データセットをクリーンにする。
  • 分析に適した形式へと構造を整える(tidy化)。
  • 列の平均や相関など、要約統計でデータを集計する。
  • データセットを可視化して洞察を得る。

pandasには時系列分析やテキストデータの分析向け機能も含まれます。

pandasの主な利点

pandasには、日々のデータ作業に役立つ5つの実用的な利点があります。

  • Python向けに設計: Pythonはデータサイエンスや機械学習で最も人気がある言語で、pandasは既存のツール群にすっと馴染みます。
  • 少ないコード量: テーブルのフィルタやグループ化、結合がループなしの1行で書けます。
  • 読みやすい表示: DataFrameはラベル付きの表として表示され、各ステップの効果が見やすくなります。
  • 機能が幅広い: 探索的分析、欠損値、要約統計、形状変更、時系列、プロットまで網羅します。
  • 数百万行を処理: メモリに収まる限り、数百万行・数百列でも動作します。より大きなデータには、PolarsやPySparkなどのツールが適しています。

pandasのインストール方法

pandasを使う前にインストールが必要です。無料のDataCampアカウント登録を行い、pandas(主要なPythonデータサイエンスパッケージ同梱)済みのクラウドIDEであるDataLabを使えば、この手順はスキップできます。

pandasをインストールする

ターミナルでpip installコマンドを使ってpandasをインストールします。pandas 3はPython 3.11以降が必要です。古いPythonでは、そのバージョンがサポートする最新のpandas 2.xがインストールされます。

pip install pandas

あるいは、conda経由でインストールすることもできます。

conda install pandas

インストール後、他パッケージとの互換性確認のためにも、バージョンを表示して動作確認しておくとよいでしょう。

import pandas as pd
print(pd.__version__)  # Prints the pandas version

これでpandasが正しく導入されたことが確認でき、他パッケージとの互換性も検証できます。

pandas 3.0と3.1の変更点

2026年1月リリースのpandas 3.0では、コピー、文字列、代入の挙動が変わり、pandas 3.1(2026年10月)では多くのinplace=Trueの使い方が非推奨になりました。古いチュートリアルのコードの多くはそのまま動きますが、特につまずきやすい変更点は次の4つです。

  • Copy-on-Writeがデフォルト。 任意の部分集合やメソッド結果はコピーとして振る舞い、変更しても元のDataFrameは変わりません。SettingWithCopyWarningは消え、防御的な.copy()呼び出しも不要です。
  • 連鎖代入は機能しません。 df["Age"][0] = 35は一時的なコピーを更新するだけでdfは変わらず、ChainedAssignmentErrorで警告されます。代わりに1回の.loc[]呼び出しを使います。
  • 文字列に専用のデータ型。 テキスト列はobjectではなくstrとして推論され、PyArrowがインストールされていればそれを基盤にします。
  • inplace=Trueが非推奨。sort_values()、reset_index()、dropna()、drop_duplicates()、rename()などで非推奨になりました。代わりに結果を再代入します(例:df = df.dropna())。

pandas 3で4つのデフォルトが変わり、古いチュートリアルを壊す可能性がある

以下は小さなDataFrameでの連鎖代入の変更例です。

import pandas as pd

patients = pd.DataFrame({"name": ["Ana", "Ben", "Chloe"], "age": [34, 51, 28]})

patients["age"][0] = 35      # chained assignment: patients is not changed
patients.loc[0, "age"] = 35  # a single .loc[] call: patients is updated
print(patients.dtypes)
name      str
age     int64
dtype: object

本チュートリアルのすべての例はpandas 3のルールに従っています。変更点の全リストは、公式リリースノートpandas 3.0とpandas 3.1をご覧ください。古いコードを保守している場合は、Copy-on-Writeに置き換えられた挙動を解説するSettingWithCopyWarningガイドが参考になります。

pandasでのデータのインポート

まず、以下のようにpandasをインポートします。pandasの一般的なエイリアスはpdです。

import pandas as pd

CSVファイルのインポート

カンマ区切り値ファイルはread_csv()にパスを渡して読み込みます(詳細はread_csv()でのインポートチュートリアルを参照)。

df = pd.read_csv("diabetes.csv")

この読み込みはdiabetes.csvをpandasのDataFramedfにロードします。本チュートリアルではPima Indians Diabetesデータセットを使用します。768人の患者、Glucose、BMI、Ageなど8つの健康指標、そして糖尿病診断を示すOutcome(1が診断あり)列を含みます。

テキストファイルのインポート

テキストファイルの読み込みはCSVと同様ですが、sep引数で区切り文字を指定する点が異なります。区切り文字は各行で値(列)を分ける文字です。よく使われるのはカンマ(sep=",")、タブ(sep="\t")、コロン(sep=":")、空白(sep=r"\s+")です。r"\s+"は1つ以上の空白文字にマッチする正規表現で、r接頭辞により生文字列として扱われ、Pythonが\sを無効なエスケープとして扱いません。

df = pd.read_csv("diabetes.txt", sep=r"\s+")

Excelファイルのインポート(単一シート)

read_excel()でファイルパスを渡して読み込みます。pandasでExcelを扱うには追加エンジンが必要です。.xlsxはopenpyxl、レガシーな.xlsはxlrdをインストールしてください。

df = pd.read_excel('diabetes.xlsx')

headerでヘッダー行(列名となる行)を指定できます。デフォルトは0(最初の行)。列名をnamesにリストで渡すこともできます。ファイルに行インデックスが含まれる場合はindex_col(デフォルトNone)を使います。

注: pandasのDataFrameやSeriesでは、インデックスは行や列の位置を指す識別子です。要するに、インデックスはDataFrameの行や列にラベルを付け、インデックスを使って特定の行・列にアクセスできます(後ほど登場)。行インデックスは範囲(例:0〜303)、時系列(日付やタイムスタンプ)、一意ID(例:employeesテーブルのemployee_ID)など様々です。列のインデックス(列名)は通常は文字列です。

Excelファイルのインポート(複数シート)

複数シートの読み込みもほぼ同様で、追加のsheet_name引数を指定します。シート名の文字列か、位置の整数を渡せます(Pythonは0始まりなので、先頭シートはsheet_name = 0)。

# Pythonは0始まりなので2番目のシートを抽出
df = pd.read_excel('diabetes_multi.xlsx', sheet_name=1)

JSONファイルのインポート

read_csv()と同様に、JSONはread_json()で読み込みます(詳細はJSONとHTMLのインポートを参照)。以下はディスク上のJSONを読み込んでDataFramedfを作成します。

df = pd.read_json("diabetes.json")

pandasでのデータ読み込みをさらに学ぶには、Pythonでさまざまなファイルタイプをインポートするためのチートシートをご覧ください。

SQLデータベースからのインポート

リレーショナルデータベースからデータを読み込むには、pd.read_sql()とDB接続を使います。

import sqlite3

# SQLiteデータベースに接続
conn = sqlite3.connect("my_database.db")

# テーブルからデータを読み込む
df = pd.read_sql("SELECT * FROM my_table", conn)

PostgreSQLやMySQLなど他のDBでは、sqlite3接続の代わりにSQLAlchemyエンジンを渡します。大きなテーブルはchunksizeでバッチ読み込みにします。

API(JSON形式)からのインポート

Web APIからデータを取得する場合、pd.read_json()で直接読み込めます。

df = pd.read_json("https://api.example.com/data.json")

APIレスポンスが入れ子のJSONなら、pd.json_normalize()でフラット化し、入れ子のキーをドット区切りの列に展開します。

records = [
    {"id": 1, "vitals": {"glucose": 148, "bmi": 33.6}},
    {"id": 2, "vitals": {"glucose": 85, "bmi": 26.6}},
]
pd.json_normalize(records)
   id  vitals.glucose  vitals.bmi
0   1             148        33.6
1   2              85        26.6

pandasでのデータのエクスポート

pandasは多様な形式へのエクスポートも可能です。pandasで変換したデータをローカルへ保存する場面で使用します。以下にDataFrameの主な出力方法を示します。

DataFrameをCSVに出力

pandas DataFrame(ここではdf)は.to_csv()でCSVに保存します。ファイルパスを渡し、行インデックスが不要ならindex=Falseを指定します(デフォルトのindex=Trueだと、無名列として追加されます)。その他の引数はCSVに保存するチュートリアルを参照してください。

df.to_csv("diabetes_out.csv", index=False)

DataFrameをJSONに出力

.to_json()でDataFrameをJSONファイルにエクスポートします。

df.to_json("diabetes_out.json")

注: JSONはDataFrameのような表をキーと値の組で保存するため、列名が繰り返し現れます。

DataFrameをテキストに出力

CSV出力と同様に.to_csv()を使いますが、拡張子を.txtにし、sepで区切り文字を指定します。

df.to_csv('diabetes_out.txt', header=df.columns, index=None, sep=' ')

DataFrameをExcelに出力

.to_excel()で.xlsxとして保存します(openpyxlが必要)。レガシーな.xlsには出力できなくなりました。

df.to_excel("diabetes_out.xlsx", index=False)

pandasでのDataFrameの確認と理解

表データをDataFrameとして読み込んだら、まず中身をざっと確認します。データセットの一部や要約統計で概要を掴めます。

データの閲覧:.head()と.tail()

先頭・末尾の数行は、それぞれ.head()・.tail()で閲覧できます。n引数で行数を指定します(デフォルトは5)。

df.head()

.head()で表示したDataFrame(df)の先頭5行

DataFrameの先頭5行

df.tail(n = 10)

.tail()で表示したDataFrameの末尾10行

DataFrameの末尾10行

データの把握:.describe()

.describe()は数値列の要約統計(件数、平均、標準偏差、範囲、四分位数など)を表示します。

df.describe()

.describe()で要約統計を取得

.describe()で要約統計を取得

これにより、数値データのスケール、歪度、範囲を素早く把握できます。

percentiles引数で四分位点を変更できます。例えば、DataFramedfの数値列について、30%、50%、70%点を表示します。

df.describe(percentiles=[0.3, 0.5, 0.7])

特定パーセンタイルでの要約統計 pandas

特定パーセンタイルでの要約統計

include引数で、出力するデータ型を限定できます。例えば、integer型の列のみを要約します。

df.describe(include=[int])

整数列のみの要約統計 pandas

整数列のみの要約統計

同様に、exclude引数で特定の型を除外することもできます。

df.describe(exclude=[int])
              BMI  DiabetesPedigreeFunction
count  768.000000                768.000000
mean    31.992578                  0.471876
std      7.884160                  0.331329
min      0.000000                  0.078000
25%     27.300000                  0.243750
50%     32.000000                  0.372500
75%     36.600000                  0.626250
max     67.100000                  2.420000


これらの統計は、.Tで転置すると見やすくなることがよくあります。

df.describe().T

要約統計を転置 pandas

.Tで要約統計を転置


DataFrameの記述に関する詳細は、以下のチートシートを参照してください。

.info()でデータを把握する

.info()は、DataFrameのデータ型、欠損数、データサイズを素早く確認する方法です。ここではshow_countsをTrueにして各列の非欠損数を表示し、memory_usageをTrueにして合計メモリ使用量も表示しています。verboseをTrueにすると.info()の完全な要約が出力されます。

df.info(show_counts=True, memory_usage=True, verbose=True)
<class 'pandas.DataFrame'>
RangeIndex: 768 entries, 0 to 767
Data columns (total 9 columns):
 #   Column                    Non-Null Count  Dtype  
---  ------                    --------------  -----  
 0   Pregnancies               768 non-null    int64  
 1   Glucose                   768 non-null    int64  
 2   BloodPressure             768 non-null    int64  
 3   SkinThickness             768 non-null    int64  
 4   Insulin                   768 non-null    int64  
 5   BMI                       768 non-null    float64
 6   DiabetesPedigreeFunction  768 non-null    float64
 7   Age                       768 non-null    int64  
 8   Outcome                   768 non-null    int64  
dtypes: float64(2), int64(7)
memory usage: 54.1 KB

.shapeで行数・列数を確認

DataFrameの行数・列数は.shape属性で取得できます。戻り値は(行, 列)のタプルで、インデックス指定で行数・列数だけ取り出せます。

df.shape # 行数・列数
df.shape[0] # 行数のみ
df.shape[1] # 列数のみ
(768,9)
768
9

全ての列と列名を取得

DataFrameオブジェクトの.columns属性は、列名をIndexとして返します。pandasのインデックスは、行や列のアドレス/ラベルを指します。

df.columns
Index(['Pregnancies', 'Glucose', 'BloodPressure', 'SkinThickness', 'Insulin', 'BMI',
       'DiabetesPedigreeFunction', 'Age', 'Outcome'],
      dtype='str')

list()でリストに変換できます。

list(df.columns)
['Pregnancies',
 'Glucose',
 'BloodPressure',
 'SkinThickness',
 'Insulin',
 'BMI',
 'DiabetesPedigreeFunction',
 'Age',
 'Outcome']

.isnull()で欠損値を確認

サンプルDataFrameには欠損がありません。ここでは例として欠損を少し加えます。.copy()で元のDataFrameのコピーを作り、以降の例に備えて元のdfを保ちます。.loc(後述)で、Pregnancies列のラベル2〜5の行を欠損に設定します。欠損値はNaN(float)で保存されるため、列の型はint64からfloat64に変わります。

df2 = df.copy()
df2.loc[2:5,'Pregnancies'] = None
df2.head(7)

2〜5行が欠損 pandas

2〜5行がNaNになっているのがわかります

各要素が欠損かどうかは.isnull()で確認できます。

df2.isnull().head(7)

どの程度欠損があるかを知るには、.isnull()と.sum()を組み合わせて列ごとの欠損数を数えます。

df2.isnull().sum()
Pregnancies                 4
Glucose                     0
BloodPressure               0
SkinThickness               0
Insulin                     0
BMI                         0
DiabetesPedigreeFunction    0
Age                         0
Outcome                     0
dtype: int64

さらに合計の欠損数は二重に合計すれば取得できます。

df2.isnull().sum().sum()
4

pandasでの並べ替え、スライス、抽出

pandasは、DataFrame内のデータを並べ替え、部分集合化、フィルタ、抽出する複数の方法を提供します。ここでは最も一般的な方法を見ていきます。

並べ替え

特定の列で並べ替えるには.sort_values()を使います。これは新しいソート済みDataFrameを返し、dfはそのままなので、保持したい場合は結果を変数に代入します。

df.sort_values(by="Age", ascending=False)  # Ageで降順

複数列での並べ替えも可能です。

df.sort_values(by=["Age", "Glucose"], ascending=[False, True])

インデックスのリセット

並べ替えやフィルタをしても元の行ラベルは保持されるため、インデックスが順序どおりでなくなることがあります。.reset_index()で0始まりの新しいインデックスにします(オプションはリセットのチュートリアル参照)。

df_sorted = df.sort_values(by="Age", ascending=False).reset_index(drop=True)  # drop=Trueで旧インデックスを破棄
df_sorted[["Age", "Glucose", "Outcome"]].head(3)
   Age  Glucose  Outcome
0   81      134        0
1   72      119        0
2   70      145        1

[ ]で1列を抽出

角括弧[ ]に列名を渡すと1列を抽出できます。出力はpandasのSeriesです。Seriesは1次元配列で、整数、浮動小数、文字列、ブール、Pythonオブジェクトなど任意の型を保持できます。DataFrameは複数のSeriesから構成されています。

df['Outcome']
0      1
1      0
2      1
3      0
4      1
      ..
763    0
764    0
765    0
766    1
767    0
Name: Outcome, Length: 768, dtype: int64

[[ ]]で複数列を抽出

列名のリストを角括弧内に渡して、2列以上を取得できます。ここでは外側の角括弧がDataFrameの部分集合、内側の角括弧がリスト生成を表します。

df[['Pregnancies', 'Outcome']]
     Pregnancies  Outcome
0              6        1
1              1        0
2              8        1
3              1        0
4              0        1
..           ...      ...
763           10        0
764            2        0
765            5        0
766            1        1
767            1        0

[768 rows x 2 columns]

[ ]で1行を抽出

Trueが1つだけのブールSeriesを渡すと単一行を取得できます。以下はindex = 1の2行目を返します。.indexは行ラベルを返し、比較でブールの1次元配列に変換されます。

df[df.index==1]

pandasで1行を抽出

pandasで1行を抽出

[ ]で複数行を抽出

同様に、==の代わりに.isin()を使えば2行以上を返せます。

df[df.index.isin(range(2,10))]

pandasで特定の行を抽出

pandasで特定の行を抽出

.loc[]と.iloc[]で行を取得

行や列、セルをラベルまたは条件で取得するには.loc[]、位置で取得するには.iloc[]("location"と"integer location")を使います。違いの詳細はloc vs ilocガイドで解説しています。ここでは、先ほど作成したdf2のインデックスを変更して、ラベルと位置が一致しない状況を作ります。

.loc[]はラベル、.iloc[]は位置で選択

df2.index = range(1,769)

以下の例はDataFrameではなくpandasのSeriesを返します。.loc[1]では、1はラベルなのでラベル1(再インデックス後の先頭行)を返します。.iloc[1]では、1は0始まりの位置なので2行目を返し、そのラベルは2です。

df2.loc[1]
Pregnancies                   6.000
Glucose                     148.000
BloodPressure                72.000
SkinThickness                35.000
Insulin                       0.000
BMI                          33.600
DiabetesPedigreeFunction      0.627
Age                          50.000
Outcome                       1.000
Name: 1, dtype: float64
df2.iloc[1]
Pregnancies                  1.000
Glucose                     85.000
BloodPressure               66.000
SkinThickness               29.000
Insulin                      0.000
BMI                         26.600
DiabetesPedigreeFunction     0.351
Age                         31.000
Outcome                      0.000
Name: 2, dtype: float64

範囲を指定して複数行を取得することもできます。両者は範囲の終端の扱いが異なります。.loc[100:110]はラベル110を含み11行を返しますが、.iloc[100:110]は位置110の手前で止まり10行を返します。

df2.loc[100:110]

locで行を抽出

.loc[]で行を抽出

df2.iloc[100:110]

.loc[]で行を抽出

.iloc[]で行を抽出

範囲の代わりにリストを使って抽出することもできます。

df2.loc[[100, 200, 300]]

.loc[]でリスト指定して行を抽出

.loc[]でリスト指定して行を抽出

df2.iloc[[100, 200, 300]]

.iloc[]で位置100, 200, 300の行を選択

.iloc[]でリスト指定して行を抽出

行と同時に列を指定して抽出することも可能です。ここで.iloc[]は列のラベルではなく「位置」を要求する点が.loc[]と異なります。

df2.loc[100:110, ['Pregnancies', 'Glucose', 'BloodPressure']]
     Pregnancies  Glucose  BloodPressure
100          1.0      122             90
101          1.0      163             72
102          1.0      151             60
103          0.0      125             96
104          1.0       81             72
105          2.0       85             65
106          1.0      126             56
107          1.0       96            122
108          4.0      144             58
109          3.0       83             58
110          0.0       95             85
df2.iloc[100:110, :3]
     Pregnancies  Glucose  BloodPressure
101          1.0      163             72
102          1.0      151             60
103          0.0      125             96
104          1.0       81             72
105          2.0       85             65
106          1.0      126             56
107          1.0       96            122
108          4.0      144             58
109          3.0       83             58
110          0.0       95             85

より高速な操作には、開始インデックス以降を範囲指定する方法もあります。

df2.loc[760:, ['Pregnancies', 'Glucose', 'BloodPressure']]
     Pregnancies  Glucose  BloodPressure
760          6.0      190             92
761          2.0       88             58
762          9.0      170             74
763          9.0       89             62
764         10.0      101             76
765          2.0      122             70
766          5.0      121             72
767          1.0      126             60
768          1.0       93             70
df2.iloc[760:, :3]
     Pregnancies  Glucose  BloodPressure
761          2.0       88             58
762          9.0      170             74
763          9.0       89             62
764         10.0      101             76
765          2.0      122             70
766          5.0      121             72
767          1.0      126             60
768          1.0       93             70

.loc[]と代入演算子=の組み合わせで値を更新できます。更新対象と同じDataFrameから条件を作ってください。dfから作った条件は新しいdf2のインデックスと揃わず、pandasはエラーを出します。

df2.loc[df2["Age"] == 81, "Age"] = 80

条件で行をフィルタ

pandasでは行・列の値に基づく条件でフィルタできます。例えば、以下は血圧がちょうど122の行を選択します。角括弧[ ]で行を抽出するのは前節と同じですが、ここでは列BloodPressureが122に等しいという条件df.BloodPressure == 122を渡しています。

df[df.BloodPressure == 122]

条件で行を抽出 pandas

条件で行を抽出

次の例はOutcomeが1の行をすべて取得します。df.Outcomeで列を選び、df.Outcome == 1でTrue/FalseのSeriesを作り、そのTrueの位置の行だけを[]で取り出します。

df[df.Outcome == 1]

条件で行を抽出 pandas

条件で行を抽出

>演算子で比較もできます。以下はBloodPressureが100より大きいレコードについて、Pregnancies、Glucose、BloodPressureを取得します。

df.loc[df['BloodPressure'] > 100, ['Pregnancies', 'Glucose', 'BloodPressure']]
     Pregnancies  Glucose  BloodPressure
43             9      171            110
84             5      137            108
106            1       96            122
177            0      129            110
207            5      162            104
362            5      103            108
369            1      133            102
440            0      189            104
549            4      189            110
658           11      127            106
662            8      167            106
672           10       68            106
691           13      158            114

pandasでのデータクレンジング

データクレンジングはデータサイエンスで最も一般的な作業の1つです。pandasは機械学習や深層学習の前処理に限らず、あらゆる用途に向けてデータを前処理できます。ここでは先ほどの欠損が4つあるdf2を使って、いくつかのクレンジング手法を示します。まず、DataFrame内の欠損数は次のように確認できます。

df2.isnull().sum()
Pregnancies                 4
Glucose                     0
BloodPressure               0
SkinThickness               0
Insulin                     0
BMI                         0
DiabetesPedigreeFunction    0
Age                         0
Outcome                     0
dtype: int64

手法1:欠損値を削除する

データ量が十分で、少しの欠損を落としても下流の分析に影響しない場合は削除が有効です。.dropna()を使います。ここでは.dropna()の結果をDataFramedf3に保存します。

df3 = df2.copy()
df3 = df3.dropna()
df3.shape
(764, 9) # df2より4行少ない

axis引数で削除対象を行か列か指定できます。デフォルトはNaNを含む行の削除です。axis = 1で1つ以上NaNを含む列を削除します。本チュートリアルの他の例と同様に、pandas 3.1で.dropna()のinplace=Trueは非推奨のため、結果を再代入しています。

df3 = df2.dropna(axis=1)
list(df3.columns)
['Glucose', 'BloodPressure', 'SkinThickness', 'Insulin', 'BMI', 'DiabetesPedigreeFunction', 'Age', 'Outcome']

デフォルトの.dropna()は、1つでも欠損があれば行を削除します。howを'all'にすると、すべての値が欠損の行のみ削除します。df2には完全に空の行がないため、何も削除されません。

df3 = df2.dropna(how="all")
df3.shape
(768, 9)

手法2:欠損値を置換する

削除の代わりに、要約統計や固定値で補完する方法もあります。例えば、1週間の気温測定で1日分が欠けている場合、その週の平均で埋めれば行は保持され、情報の損失も小さくて済みます。以下はPregnanciesの欠損を列平均で埋めています。

df3 = df2.copy()
# Pregnanciesの平均を取得
mean_value = df3["Pregnancies"].mean()
# その列の欠損のみを補完
df3["Pregnancies"] = df3["Pregnancies"].fillna(mean_value)
df3["Pregnancies"].head(7)
1    6.000000
2    1.000000
3    3.846859
4    3.846859
5    3.846859
6    3.846859
7    3.000000
Name: Pregnancies, dtype: float64

重複データへの対処

重複除去を学ぶため、元データに重複を追加します。pd.concat()でdf2を自分自身と縦結合し、df2の各行を完全に重複させます。

df3 = pd.concat([df2, df2])
df3.shape
(1536, 9)

すべての重複行(デフォルト)を.drop_duplicates()で除去できます。

df3 = df3.drop_duplicates()
df3.shape
(768, 9)

列名の変更

よくあるクレンジング作業に列名の変更があります。.rename()に古い名前から新しい名前へのマッピングをcolumns辞書で渡します。

df3 = df3.rename(columns={"DiabetesPedigreeFunction": "DPF"})
df3[["Glucose", "BMI", "DPF", "Age"]].head()
   Glucose   BMI    DPF  Age
1      148  33.6  0.627   50
2       85  26.6  0.351   31
3      183  23.3  0.672   32
4       89  28.1  0.167   21
5      137  43.1  2.288   33

また、.columnsに列名のリストを一括代入することもできます。リストは現在の列順すべてに対応している必要があります。pandasは位置で割り当てるため、順序が合わないとデータに誤ったラベルが静かに付与されます。

df3.columns = ["Pregnancies", "Glucose", "BloodPressure", "SkinThickness", "Insulin", "BMI", "DPF", "Age", "Outcome"]
list(df3.columns)
['Pregnancies', 'Glucose', 'BloodPressure', 'SkinThickness', 'Insulin', 'BMI', 'DPF', 'Age', 'Outcome']

データクレンジングの詳細や、より簡潔で予測可能なワークフローについては、一般的なデータクレンジングのチェックリストをご活用ください。

pandasでDataFrameを結合する

pandasは2つの方法でDataFrameを結合します。.merge()は共有キー列でテーブルを結合(SQLのJOINのように)、pd.concat()はテーブルを上下または左右に連結します。

.merge()での結合

2つのテーブルがキー列を共有しているときは.merge()を使います。例えば、Outcomeコードごとに読みやすいラベルを持つ第2テーブルがあるとします。Outcomeでの左結合により、各患者行にラベルを追加します。

outcome_labels = pd.DataFrame({"Outcome": [0, 1], "Diagnosis": ["Non-diabetic", "Diabetic"]})

df_labeled = df.merge(outcome_labels, on="Outcome", how="left")
df_labeled[["Glucose", "Outcome", "Diagnosis"]].head(3)
   Glucose  Outcome     Diagnosis
0      148        1      Diabetic
1       85        0  Non-diabetic
2      183        1      Diabetic

how引数で結合タイプを指定します。"left"はdfの全行を保持、"inner"は両テーブルに一致がある行のみ、"outer"は両方の全行を保持します。詳細はDataFrame結合チュートリアルをご覧ください。

pd.concat()での連結

同じ列構成のテーブルの行を積み上げたい(例:2回に分かれて届いた患者記録)ときはpd.concat()を使います。ignore_index=Trueで、各バッチのラベルを保持せず0始まりの新しいインデックスにします。

batch_1 = df.iloc[:500]
batch_2 = df.iloc[500:]

df_combined = pd.concat([batch_1, batch_2], ignore_index=True)
df_combined.shape
(768, 9)

axis=1を指定すると、インデックスラベルで行を対応付けながら左右に並べます。

measurements = df[["Glucose", "BMI"]]
outcomes = df[["Outcome"]]

pd.concat([measurements, outcomes], axis=1).head(3)
   Glucose   BMI  Outcome
0      148  33.6        1
1       85  26.6        0
2      183  23.3        1

両手法の実践には、Joining Data with pandasコースをお試しください。

pandasでのデータ分析

pandasの価値は、素早いデータ分析機能にあります。ここでは、pandasで使える代表的な分析手法を紹介します。

要約演算(平均・最頻値・中央値)

前述のとおり、各列の平均は.mean()で取得できます。

df.mean()
Pregnancies                   3.845052
Glucose                     120.894531
BloodPressure                69.105469
SkinThickness                20.536458
Insulin                      79.799479
BMI                          31.992578
DiabetesPedigreeFunction      0.471876
Age                          33.240885
Outcome                       0.348958
dtype: float64

最頻値は.mode()で同様に求められます。

df.mode()

各列の最頻値 pandas

pandasで列の最頻値を表示

中央値は.median()で計算します。

df.median()
Pregnancies                   3.0000
Glucose                     117.0000
BloodPressure                72.0000
SkinThickness                23.0000
Insulin                      30.5000
BMI                          32.0000
DiabetesPedigreeFunction      0.3725
Age                          29.0000
Outcome                       0.0000
dtype: float64

既存列から新しい列を作る

pandasは、2つ以上の列同士をスカラーのように組み合わせて高速に計算できます。以下はGlucoseをInsulinで割って、新しい列Glucose_Insulin_Ratioを作っています。

df2['Glucose_Insulin_Ratio'] = df2['Glucose']/df2['Insulin']
df2.head()

既存列から新しい列を作成 pandas

既存列から新しい列を作成

Insulinが0の行は、0で割っているためinfになります。このデータセットではInsulinの0は測定欠損(768行中374行)を意味するため、割る前に0を欠損として扱います。

df2["Glucose_Insulin_Ratio"] = df2["Glucose"] / df2["Insulin"].where(df2["Insulin"] > 0)
df2["Glucose_Insulin_Ratio"].head()
1         NaN
2         NaN
3         NaN
4    0.946809
5    0.815476
Name: Glucose_Insulin_Ratio, dtype: float64

.where()は条件を満たす値を残し、それ以外をNaNに置き換えます。これで比率は無限大ではなく欠損になります。さらに詳しい列の派生はpandasで列を追加をご覧ください。

.value_counts()で件数を数える

カテゴリを保持する列では、各カテゴリの観測数を数えたくなることがよくあります。これには.value_counts()を使います。以下ではOutcomeが糖尿病(1)と非糖尿病(0)の件数を数えています。

df['Outcome'].value_counts()
Outcome
0    500
1    268
Name: count, dtype: int64

normalizeを指定すると、件数ではなく比率を返します。

df['Outcome'].value_counts(normalize=True)
Outcome
0    0.651042
1    0.348958
Name: proportion, dtype: float64


結果の自動ソートはsort引数(デフォルトTrue)で無効化できます。デフォルトでは件数の降順です。

df['Outcome'].value_counts(sort=False)
Outcome
1    268
0    500
Name: count, dtype: int64

.value_counts()は列だけでなく、DataFrameとその特定の列集合にも適用できます。以下ではsubset引数に列リストを渡しています。

df.value_counts(subset=['Pregnancies', 'Outcome'])
Pregnancies  Outcome
1            0          106
2            0           84
0            0           73
3            0           48
4            0           45
0            1           38
5            0           36
6            0           34
1            1           29
3            1           27
7            1           25
4            1           23
8            1           22
5            1           21
7            0           20
2            1           19
9            1           18
6            1           16
8            0           16
10           0           14
             1           10
9            0           10
11           1            7
13           0            5
             1            5
12           0            5
11           0            4
12           1            4
14           1            2
15           1            1
17           1            1
Name: count, dtype: int64

pandasの.groupby()で集計

.groupby()と要約メソッドを組み合わせると、特定の列値でグループ化して集計できます。以下はOutcomeごとに数値列の平均を表示します。

df.groupby('Outcome').mean()

1列でのグループ化集計 pandas

1列でのグループ化集計

.groupby()は列名のリストを渡すことで複数列でもグループ化できます。

df.groupby(['Pregnancies', 'Outcome']).mean()

2列でのグループ化集計 pandas

2列でのグループ化集計

使用できる要約メソッドは.min()、.max()、.mean()、.median()、.sum()などです。複数集計の.agg()などのパターンはpandas GroupByチュートリアルで解説しています。

ピボットテーブル

pandasではピボットテーブルでも要約統計を計算できます。複数の変数の組み合わせで結論を導きやすくなります。以下は行がPregnanciesの一意値、列がOutcomeの一意値、セルが該当グループのBMI平均です。

例えば、Pregnancies = 5かつOutcome = 0では平均BMIは31.1です。

pd.pivot_table(df, values="BMI", index='Pregnancies', 
               columns=['Outcome'], aggfunc='mean')
Outcome              0          1
Pregnancies                      
0            31.727397  39.213158
1            29.616038  37.793103
2            29.679762  34.578947
3            29.231250  32.548148
4            31.255556  33.873913
5            31.100000  36.780952
6            29.591176  31.775000
7            29.975000  34.756000
8            30.693750  32.204545
9            28.840000  33.300000
10           30.114286  31.380000
11           37.125000  39.385714
12           30.560000  34.575000
13           33.280000  36.720000
14                 NaN  35.100000
15                 NaN  37.100000
17                 NaN  40.900000

pandasでのデータ可視化

pandasは、Matplotlibのプロット関数に対する便利なラッパーを提供し、DataFrameの可視化を容易にします。以下では一般的な可視化をpandasで行う方法を示します。

折れ線グラフ

pandasでは、変数間の関係を折れ線で描画できます。以下は行インデックスに対するBMIとGlucoseの折れ線グラフです。

df[['BMI', 'Glucose']].plot.line()

pandasの基本的な折れ線グラフ

pandasの基本的な折れ線グラフ

色はcolor引数で指定できます。

df[['BMI', 'Glucose']].plot.line(color={"BMI": "red", "Glucose": "blue"})

カスタム色を使った基本的な折れ線グラフ

カスタム色を使った基本的な折れ線グラフ

また、subplots引数で、dfの全列を個別のスケール・軸で描画できます。

df.plot.line(subplots=True)

pandasの折れ線グラフをサブプロットで表示

折れ線グラフのサブプロット

棒グラフ

離散的な列は、カテゴリ件数の棒グラフで分布を可視化できます。二値のOutcomeを以下に示します。

df['Outcome'].value_counts().plot.bar()

Outcomeの件数の棒グラフ pandas

pandasの棒グラフ

箱ひげ図

連続変数の四分位の分布は箱ひげ図で可視化できます。以下のコードで作成します。

df.boxplot(column=['BMI'], by='Outcome')

pandasの箱ひげ図
pandasの箱ひげ図

まとめ

これでpandasの中核ワークフローを身につけました。ファイルをDataFrameに読み込み、.head()、.info()、.describe()で確認し、.loc[]と.iloc[]で行を選択、欠損や重複をクリーンにし、テーブルを結合、.groupby()やピボットテーブルで要約します。

2026年以前にpandasを学んだ方は、習慣を1つ変える価値があります。inplace=Trueではなく結果を再代入し、更新は常に1回の.loc[]呼び出しで行ってください。残りを定着させる最速の方法は、関心のあるデータセットでこのワークフローを繰り返すことです。さらに学ぶには以下をどうぞ。

pandasのFAQ

Pythonにおけるpandasとは?

pandasは表形式データを扱うためのオープンソースのPythonライブラリです。2つの中核データ構造であるDataFrame(表)とSeries(単一列)は、データのインポート、クレンジング、形状変更、集計、プロットのための関数を備えており、Pythonでのデータ分析の標準ツールとなっています。

なぜpandasを学ぶべきですか?

Pythonでデータを扱うなら、pandasはほぼ必須です。データの取り扱いと分析を簡素化し、洞察の抽出と価値創出に集中できます。小規模データから大規模データまで、pandasはその速度、柔軟性、使いやすいデータ構造で作業を楽にしてくれます。

pandasはどうやってインストールしますか?

ターミナルでpip install pandasを実行するか、conda利用時はconda install pandasを実行します。pandas 3はPython 3.11以降が必要です。Anacondaには標準で同梱され、DataCampのDataLabでも事前インストールされています。

pandasの基本的なデータ構造は何ですか?

pandasの主なデータ構造はSeriesとDataFrameです。Seriesは基本的に1つの列、DataFrameは複数のSeriesからなる多次元の表です。これらは柔軟で、整数、文字列、浮動小数など異なる型のデータを保持できます。

pandasは大規模データに向いていますか?

pandasはデータがPCメモリに収まる限り、数百万行でも快適に扱えます。収まらない場合はchunksizeで分割読み込みするか、Polars、Dask、PySparkなどの大規模データ向けツールに切り替えてください。

pandasへはどうやってデータをインポートしますか?

pandasはCSV、Excel、SQLデータベース、JSONなど多様な形式からデータを読み込めます。pd.read_csv()、pd.read_excel()、pd.read_sql()、pd.read_json()がそれぞれの形式に対応します。いずれもDataFrameを返し、pandasで操作できます。

pandas 3.0では何が変わりましたか?

2026年1月リリースのpandas 3.0ではCopy-on-Writeがデフォルトになり、あらゆる部分集合はコピーとして振る舞うため、df["col"][0] = xのような連鎖代入は元のDataFrameを更新しません。テキスト列は専用のstr型として推論され、Python 3.11以降が必要になりました。続くpandas 3.1では、dropna()やsort_values()などでinplace=Trueが非推奨になりました。

pandasにおけるlocとilocの違いは?

.loc[]はラベルで行・列を選択し、.iloc[]は0始まりの整数位置で選択します。スライスも異なり、.loc[100:110]は終端ラベルを含み、.iloc[100:110]は位置110の手前までです。詳しくはloc vs ilocガイドをご覧ください。

pandasで2つのDataFrameを結合するには?

SQLのJOINのように、共有列で2つのDataFrameを結合するにはdf1.merge(df2, on="key", how="left")を使います。howで"left"、"right"、"inner"、"outer"を選べます。行を積み上げるならpd.concat()を使います。

トピック