【Pandas】DataFrameとSeriesの基本を理解する

Pandas

こんにちは、かつコーチです。
pandasを学び始めると必ず出てくるのがDataFrameSeriesという2つの言葉です。
「同じようなものに見えるけど、何が違うの?」と混乱してしまう方も多いので、この記事で違いと使い分けをしっかり整理します。

DataFrameとSeriesとは?

Seriesの定義:1列分のデータ

Series(シリーズ)とは、ラベル(見出し)付きの1次元のデータのことです。
Excelでいうと「1列分のデータ」に近いイメージです。

import pandas as pd

ages = pd.Series([25, 30, 28], name="年齢")
print(ages)
0    25
1    30
2    28
Name: 年齢, dtype: int64

左側の0, 1, 2インデックス(各データの位置を示すラベル)と呼ばれるものです。

DataFrameの定義:複数列を持つ表全体

DataFrame(データフレーム)とは、複数のSeriesを列として束ねた、2次元の表形式データのことです。
Excelでいう「シート全体」に近いイメージです。

import pandas as pd

data = {
    "名前": ["田中", "佐藤", "鈴木"],
    "年齢": [25, 30, 28]
}
df = pd.DataFrame(data)
print(df)
   名前  年齢
0  田中   25
1  佐藤   30
2  鈴木   28

つまり、DataFrameから1列だけを取り出すとSeriesになる、という関係にあります。

なぜ2つを区別する必要があるのか

DataFrameとSeriesでは、使えるメソッドや戻り値の形が異なります。
この違いを理解していないと、「あるメソッドがDataFrameでは使えるのにSeriesでは使えない」といったエラーに遭遇したときに原因が分からず戸惑ってしまいます。

例えば、DataFrameの列を1つ取り出すとSeriesになるため、その後の処理も「1列分のデータに対する処理」として書く必要があります。

基本の書き方:DataFrameとSeriesを行き来する

DataFrameから列を取り出すとSeriesになる

import pandas as pd

df = pd.DataFrame({
    "名前": ["田中", "佐藤", "鈴木"],
    "年齢": [25, 30, 28]
})

age_series = df["年齢"]
print(type(age_series))  # <class 'pandas.core.series.Series'>

DataFrameから複数列を取り出すとDataFrameのまま

一方、列名をリストで指定すると、結果は1列でもDataFrameのままになります。

age_df = df[["年齢"]]
print(type(age_df))  # <class 'pandas.core.frame.DataFrame'>

df["年齢"]df[["年齢"]]、見た目はカッコの数が違うだけですが、返ってくる型がまったく異なります。
これは初心者がつまずきやすいポイントの1つです。

型・列名・行数を確認する基本メソッド

DataFrameの中身をざっくり把握するには、以下のメソッドが便利です。

print(df.shape)    # (行数, 列数) を表示 -> (3, 2)
print(df.columns)  # 列名の一覧
print(df.dtypes)   # 各列のデータ型
print(df.info())   # 行数・列名・型・欠損値の有無をまとめて表示

特にdf.info()は、データを読み込んだ直後に必ず実行する習慣をつけておくと、後々のトラブルを防げます。

よくあるつまずきポイント・エラー対処

Series同士の計算で行の対応がずれる

❌Before:インデックスが異なるSeries同士を単純に足し算してしまう

import pandas as pd

s1 = pd.Series([100, 200, 300], index=[0, 1, 2])
s2 = pd.Series([10, 20, 30], index=[1, 2, 3])

result = s1 + s2
print(result)
0      NaN
1    210.0
2    320.0
3      NaN
dtype: float64

実際に私がこのコードを初めて実行したとき、「なぜ全部の行が計算されずにNaNが混ざるのか」で数十分悩みました。
原因は、pandasが計算をインデックスをキーにして自動的に対応付ける仕組みになっているためです。
インデックスが一致しない03の行は、計算できずにNaN(欠損値)になります。

✅After:計算前にreset_index(drop=True)でインデックスを揃えるか、そもそも同じインデックスを持つデータ同士で計算する

s1_reset = s1.reset_index(drop=True)
s2_reset = s2.reset_index(drop=True)
result = s1_reset + s2_reset
print(result)

「pandasは行番号ではなくインデックスで対応付けている」という前提を知っているかどうかで、原因究明にかかる時間が大きく変わります。

応用・一歩先の使い方

DataFrameの行方向にも同じ考え方が使える

ここまでは列(Series)を中心に説明しましたが、行方向にも同様の考え方があります。
df.loc[0]のように行を1行だけ取り出すと、その行はSeriesとして返されます。
行・列どちらの方向でも「1本だけ取り出すとSeries、複数まとめるとDataFrame」というルールは共通です。

メソッドチェーンで処理をつなげる

DataFrameのメソッドは、多くが処理後のDataFrameやSeriesを返すため、.でつなげて書くことができます。

result = df["年齢"].mean()
print(result)  # 27.666...

このように処理を連結して書くスタイルは、pandasのコードでは非常によく使われるので、慣れておくと後の記事の理解がスムーズになります。

まとめ

この記事のポイント

  • Seriesは1列分のラベル付きデータ、DataFrameは複数列を束ねた表全体
  • df["列名"]はSeries、df[["列名"]]はDataFrameになる(カッコの数に注意)
  • df.shapedf.columnsdf.info()でデータの全体像を把握する習慣をつける
  • pandasの計算はインデックスをキーに自動対応付けされる点に注意する

次に読むべき記事

DataFrameとSeriesの違いが分かったら、次は実際のデータをCSVファイルから読み込む方法を解説した「read_csvでCSVファイルを読み込む方法とよくあるハマりどころ」に進みましょう。

タグ: Pandas, 初心者向け, 基本操作

タイトルとURLをコピーしました