コンテンツにスキップ

単元 4:Pandas と DataFrame 入門

  • pandas をインポートし、SeriesDataFrame を生成できる
  • shape / columns / dtypes / info() で DataFrame の全体像を把握できる
  • df["列名"] で列を、df.iloc[i] / df.loc[label] で行を、df.loc[行, 列] でセルを取り出せる
  • Series と DataFrame の違いを 1 行で説明できる

Python だけでも CSV ファイルを 1 行ずつ読み込んで処理することはできます。ただし「表形式のデータ」を扱うとなると、行と列の構造を自分で管理しないといけないので、すぐに煩雑になります。

pandas は「表をオブジェクトとして扱う」ためのライブラリで、Python のデータ分析の事実上の標準になっています。CSV を 1 行で読み込み、列を指定して集計し、結果を CSV に書き戻す、という一連の操作がすべてこのライブラリ内で完結します。本コースで扱う集計・前処理・可視化はすべて pandas を中心に進めます。

Colab には pandas が最初からインストールされているので、import するだけで使えます。

import pandas as pd

pd という短い別名を付けるのが慣例で、世界中のサンプルコードがこの書き方をしています。本コースでも以後 pd で統一します。

Series — 1 列ぶんの「ラベル付き配列」

Section titled “Series — 1 列ぶんの「ラベル付き配列」”

pandas の最も基本的なデータ構造が Series(シリーズ) です。Python の標準のリストに似ていますが、各要素に インデックス(ラベル) がついている点が違います。

s = pd.Series([10, 20, 30], index=["a", "b", "c"])
s

実行すると次のように表示されます:

a 10
b 20
c 30
dtype: int64

左側の a, b, c がインデックス、右側の 10, 20, 30 が値です。値を取り出すときはラベルでアクセスできます:

s["a"] # → 10

整数の位置でもアクセスできますが(s[0])、ラベルを付けられるのが Series の利点です。後で DataFrame を扱うとき、この「ラベル」が列名として活きてきます。

DataFrame — 表(複数の Series の集まり)

Section titled “DataFrame — 表(複数の Series の集まり)”

実際の業務や研究では 1 列だけのデータより、Excel のシートのような を扱う場面の方が圧倒的に多くなります。表は DataFrame(データフレーム) として扱います。

DataFrame は「複数の Series が縦に並んだもの」と考えると分かりやすいです。次は辞書から DataFrame を作る例:

df = pd.DataFrame({
"name": ["太郎", "花子", "一郎"],
"age": [25, 30, 22],
"city": ["東京", "大阪", "福岡"],
})
df

出力:

name age city
0 太郎 25 東京
1 花子 30 大阪
2 一郎 22 福岡

辞書のキー(name, age, city)が 列名 になり、リストの中身が各列の値として並びます。左端の 0, 1, 2行のインデックス(デフォルトでは整数の連番)。

新しいデータを開いたら、いきなり中身を加工する前に まず全体像を眺めるのが定石です。次の 6 つを順番に呼ぶだけで、データの規模・列構成・型・分布の感触がつかめます。

メソッド/属性内容
df.shape(行数, 列数) のタプル
df.columns列名の一覧
df.dtypes各列のデータ型(数値か文字列か)
df.info()列数・行数・型・欠損数をまとめて表示
df.head()先頭 5 行(引数で件数指定可:df.head(10)
df.describe()数値列の要約統計(平均・標準偏差・最小・最大ほか)

実際に呼んでみると次のような流れになります:

print(df.shape) # (3, 3)
print(df.columns) # Index(['name', 'age', 'city'], dtype='object')
print(df.dtypes)
df.info()
df.head()
df.describe()

describe()数値列だけ を対象にすることに注意。文字列の列(name, city)は集計対象から外れます。

特定の列だけを取り出す書き方は 2 つあります:

df["name"] # 1 列だけ → Series が返る
df[["name", "age"]] # 複数列 → DataFrame が返る(リストで囲む)

df["name"]df[["name"]]見た目が似ているが戻り値の型が違う 点に注意してください。前者は Series(1 列分のラベル付き配列)、後者は DataFrame(1 列だけの表)です。可視化など「DataFrame を渡したい」場面では後者を使い分けます。

行を取り出すには 2 つの基本方法があります:

df.iloc[0] # 位置で取り出す:先頭行
df.iloc[-1] # 末尾行
df.iloc[0:2] # スライス:0 行目と 1 行目(2 行目は含まない)
df.loc[0] # ラベルで取り出す:インデックスラベルが 0 の行
  • ilocinteger location(位置) で指定
  • loclabel(ラベル) で指定

デフォルトのインデックスは整数の連番(0, 1, 2, ...)なので両者は似た見た目になりますが、インデックスを別の値(たとえば学籍番号や日付)に振り直すと挙動が分かれます。最初のうちは「数字で当てるなら iloc、名前で当てるなら loc」と覚えておけば十分です。

セル(特定の値)にアクセスする

Section titled “セル(特定の値)にアクセスする”

1 つのセルだけを取り出すなら:

df.loc[0, "age"] # 行ラベル 0、列名 "age" の値 → 25
df.at[0, "age"] # 単一セルの高速版

普段は loc で十分ですが、ループ内で何千回も単一セルにアクセスする場面では at の方が体感で速くなります。

  • df["name"]df[["name"]] — 戻り値の型(Series か DataFrame か)が違う。可視化メソッドに渡すと挙動が変わる
  • df.iloc[0]df.loc[0] — デフォルトでは見た目が同じだが、インデックスを振り直すと別物になる
  • df.head()df.head() を付け忘れると関数オブジェクトを返すだけで実行されない

この辺は最初は混乱しますが、3 回ほど自分で書けば自然に区別がつくようになります。

Drive にアップロードした users.csv を Colab で開く例:

from google.colab import drive
drive.mount('/content/drive')
import pandas as pd
df = pd.read_csv("/content/drive/MyDrive/datasets/users.csv")
print(df.shape)
print(df.columns.tolist())
df.dtypes

users.csv を Colab に読み込み、次の操作を順番に試してください。

  1. df.shape / df.columns / df.dtypes を表示する
  2. 「年齢」列だけを Series として取り出して表示する
  3. 「名前」と「都市」の 2 列だけを DataFrame として表示する
  4. iloc[0] で先頭行を取り出して表示する
  5. df.loc[0, "年齢"] で「太郎の年齢」を単一値として取り出す

各操作の出力を見て、戻り値の型(Series か DataFrame か単一値か)を意識しながら進めると、本文の説明と結びつきやすくなります。

  • 辞書から自分で 5 行 4 列の DataFrame を作成し、head() / tail() / describe() を呼んでみる
  • df["年齢"] + 1 のように Series 全体に演算をかけて、新しい列 年齢_翌年 を作成する
  • df.sort_values("年齢") で年齢順に並べ替えて表示する(次回以降の単元で詳しく扱います)