Pandas DataFrameとは?作り方・基本操作・Seriesとの違いを初心者向けに解説

Pandasを学び始めると、最初に登場するのがDataFrame(データフレーム)です。しかし、pd.DataFrame()で表を作れても、「辞書とリストのどちらを使うのか」「表示された表のどこを確認するのか」「次に何をすればよいのか」で迷いやすいものです。

この記事では、Google Colabで小さな売上データを作り、作成→確認→列選択→列追加→条件抽出→並べ替え→集計までを同じDataFrameで実行します。コードを動かすだけでなく、出力の行・列・型を読み、想定外の結果を自分で確認する方法まで身につけます。

  1. この記事でわかること
  2. 先に結論:DataFrameは複数列を持つ表形式データに使う
  3. 辞書から売上DataFrameを作る
    1. 実行目的と実行前の状態
  4. DataFrameの行・列・インデックスを確認する
    1. 図解:DataFrameのどこが行・列・インデックスか
  5. 辞書のリストから作る場合との違い
  6. 作成後は5項目を確認する
  7. DataFrameとSeriesを使い分ける
  8. 同じDataFrameで基本操作をつなげる
    1. 必要な列を選ぶ
    2. 売上列を追加する
    3. 売上1,000円以上の商品を抽出する
    4. 売上の高い順に並べる
    5. カテゴリ別に売上を集計する
  9. コードは動くが結果を誤解しやすい例
    1. 数字が文字列のままでもDataFrameは作れる
    2. 抽出・並べ替えは元データを自動変更しない
  10. DataFrame作成時のエラーを確認して修正する
    1. NameError: name 'pd' is not defined
    2. ValueError: All arrays must be of the same length
    3. KeyErrorで列を選べない
  11. 自分のデータへ置き換えるときのチェックリスト
  12. DataFrameから次の分析へ進む
  13. まとめ
  14. 関連記事
    1. カテゴリから探す
    2. DataFrameとSeriesはどう使い分けますか?
    3. 辞書と辞書のリストでは、どちらからDataFrameを作ればよいですか?
    4. df["列名"]とdf[["列名"]]は何が違いますか?
    5. All arrays must be of the same lengthはどう直しますか?
    6. DataFrameを作った後、最初に何を確認すればよいですか?
    7. 行を追加するときにappend()を使ってもよいですか?

この記事でわかること

  • DataFrameの行・列・インデックスの意味
  • 元データの形に合うDataFrameの作り方
  • 作成後にshapecolumnsdtypeshead()info()で確認する手順
  • DataFrameとSeries、df["列名"]df[["列名"]]の違い
  • 列追加・条件抽出・並べ替え・集計の基本的な流れ
  • 列の長さ、列名、データ型が原因の失敗を確認して直す方法

DataFrameはPandas学習の入口です。ここで全操作を暗記する必要はありません。まず表を正しく作って確認し、目的に合う個別の操作へ進めるようになることが目標です。

先に結論:DataFrameは複数列を持つ表形式データに使う

DataFrameは、行と列で構成され、列ごとに異なるデータ型を持てる2次元のデータ構造です。Excelの表に似ていますが、Pythonコードで確認・加工・集計を再現できる点が特徴です。

元データの状態に応じて、最初の作り方を選びます。

元データの状態 選ぶ方法 最小構文 向いている場面
列ごとに値がまとまっている 辞書から作る pd.DataFrame(data) 小さな練習データ、列単位のデータ
1件ずつ行としてまとまっている 辞書のリストから作る pd.DataFrame(records) API結果、レコード形式のデータ
CSVファイルに保存されている CSVを読み込む pd.read_csv(path) 実務データ、配布データ
Excelファイルに保存されている Excelを読み込む pd.read_excel(path) シート形式の業務データ

どの方法でも、作成後はすぐ加工せず、行数・列名・データ型・欠損・先頭の値を確認します。

辞書から売上DataFrameを作る

実行目的と実行前の状態

商品名・カテゴリ・単価・数量が列ごとにまとまった辞書を、DataFrameへ変換します。各列の要素数は4件でそろえています。

import pandas as pd

data = {
    "商品名": ["ノート", "ペン", "電卓", "ファイル"],
    "カテゴリ": ["文具", "文具", "事務用品", "文具"],
    "単価": [120, 80, 1500, 300],
    "数量": [3, 10, 2, 5],
}

df = pd.DataFrame(data)
df
商品名 カテゴリ 単価 数量
0 ノート 文具 120 3
1 ペン 文具 80 10
2 電卓 事務用品 1500 2
3 ファイル 文具 300 5

辞書のキーが列名になり、各リストの同じ位置にある値が1行になります。左端の03インデックスです。通常のデータ列ではなく、行を識別するラベルとして使われます。

最初に見るのは、列名が「商品名・カテゴリ・単価・数量」になっているか、4行すべてが表示されているか、値が意図した列に入っているかです。

DataFrameの行・列・インデックスを確認する

図解:DataFrameのどこが行・列・インデックスか

インデックス(行ラベル)↓/列名→ 商品名 カテゴリ 単価 数量
0 ノート 文具 120 3
1 ペン 文具 80 10

上端の「商品名・カテゴリ・単価・数量」が列名、左端の01インデックス、横方向の1組がです。たとえば、インデックス0と「単価」が交差するセルの値は120です。

要素 このDataFrameでの例 意味
03の4行 1件分のデータ
商品名、カテゴリ、単価、数量 同じ種類の値のまとまり
インデックス 0123 行を識別するラベル
セル 商品名列の「ノート」など 行と列が交差する1つの値

shapeは行数と列数、columnsは列名、indexは行ラベルを返します。

print("行数・列数:", df.shape)
print("列名:", df.columns.tolist())
print("インデックス:", df.index.tolist())
行数・列数: (4, 4)
列名: ['商品名', 'カテゴリ', '単価', '数量']
インデックス: [0, 1, 2, 3]

df.shapeの結果は(4, 4)です。先が行数、後ろが列数なので、「4行4列」と読みます。columnsindexも、作成前の想定と一致していることを確認します。

辞書のリストから作る場合との違い

1件ずつ「商品名・カテゴリ・単価・数量」がまとまっている場合は、辞書のリストが自然です。作り方は異なっても、完成する表の形は同じです。

records = [
    {"商品名": "ノート", "カテゴリ": "文具", "単価": 120, "数量": 3},
    {"商品名": "ペン", "カテゴリ": "文具", "単価": 80, "数量": 10},
    {"商品名": "電卓", "カテゴリ": "事務用品", "単価": 1500, "数量": 2},
    {"商品名": "ファイル", "カテゴリ": "文具", "単価": 300, "数量": 5},
]

df_records = pd.DataFrame(records)
df_records
商品名 カテゴリ 単価 数量
0 ノート 文具 120 3
1 ペン 文具 80 10
2 電卓 事務用品 1500 2
3 ファイル 文具 300 5

列ごとの辞書を無理に辞書のリストへ直す必要はありません。元データが列単位なら辞書、行単位なら辞書のリストと判断すると迷いにくくなります。

CSVを使う場合は、ファイルパスを指定してpd.read_csv("ファイルパス")とします。Google ColabへのアップロードやDrive接続は、Google ColabでCSVを読み込む方法で詳しく確認できます。Excelの場合はpandas read_excel()の使い方へ進んでください。

作成後は5項目を確認する

DataFrameが表示されても、中身が正しいとは限りません。加工前に次の5項目を確認します。

  1. shape:想定した行数と列数か
  2. columns:列名の空白や表記違いがないか
  3. dtypes:数値や日付が適切な型か
  4. head():先頭の値と列の対応が正しいか
  5. info():Non-Null Countと型に異常がないか

まず、先頭行とデータ型を確認します。

print(df.head())
print("\nデータ型:")
print(df.dtypes)
    商品名  カテゴリ    単価  数量
0   ノート    文具   120   3
1    ペン    文具    80  10
2    電卓  事務用品  1500   2
3  ファイル    文具   300   5

データ型:
商品名     object
カテゴリ    object
単価       int64
数量       int64
dtype: object

商品名カテゴリは文字列を持つobject型、単価数量は整数のint64型です。今回の売上計算では単価と数量が数値型であることが重要です。

head()は先頭だけを確認するメソッドです。全行の欠損や異常を保証するものではありません。詳しい使い分けはpandas head()の使い方を参照してください。

df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 4 entries, 0 to 3
Data columns (total 4 columns):
 #   Column  Non-Null Count  Dtype 
---  ------  --------------  ----- 
 0   商品名     4 non-null      object
 1   カテゴリ    4 non-null      object
 2   単価      4 non-null      int64 
 3   数量      4 non-null      int64 
dtypes: int64(2), object(2)
memory usage: 260.0+ bytes

info()では4行すべてについて各列のNon-Null Count4 non-nullなので、この例に欠損値はありません。Non-Null Countは欠損数ではなく、欠損していない値の数です。

実データで構造・型・欠損を診断する方法はpandas info()の使い方、値の分布はpandas describe()の使い方で確認できます。

DataFrameとSeriesを使い分ける

DataFrameは2次元の表、Seriesは1次元のデータです。同じ1列を選んでも、角括弧の数で戻り値が変わります。

書き方 戻り値 次元 選ぶ場面
df["単価"] Series 1次元 1列を計算・集計したい
df[["単価"]] DataFrame 2次元 1列でも表形式を保ちたい

実際の型と表示の違いを確認します。

price_series = df["単価"]
price_frame = df[["単価"]]

print("1組の角括弧:", type(price_series).__name__, price_series.shape)
print("2組の角括弧:", type(price_frame).__name__, price_frame.shape)
price_frame
1組の角括弧: Series (4,)
2組の角括弧: DataFrame (4, 1)
単価
0 120
1 80
2 1500
3 300

price_seriesの形は(4,)price_frame(4, 1)です。見た目が似ていても型と次元が違うため、後続処理がDataFrameを前提にする場合はdf[["単価"]]を選びます。

同じDataFrameで基本操作をつなげる

ここからは、作成したdfを使って、列選択・計算列追加・条件抽出・並べ替え・集計を順番に行います。個別メソッドの引数を網羅するのではなく、DataFrameを分析へつなげる全体像を確認します。

必要な列を選ぶ

複数列をDataFrameとして残すため、列名をリストで指定します。

selected = df[["商品名", "単価", "数量"]]
selected
商品名 単価 数量
0 ノート 120 3
1 ペン 80 10
2 電卓 1500 2
3 ファイル 300 5

3列だけを持つDataFrameが返りました。元のdfは削除されず、4列のまま残っています。

売上列を追加する

元データを残して処理前後を比較できるように、copy()df_salesを作ってから「単価×数量」を計算します。

df_sales = df.copy()
df_sales["売上"] = df_sales["単価"] * df_sales["数量"]
df_sales
商品名 カテゴリ 単価 数量 売上
0 ノート 文具 120 3 360
1 ペン 文具 80 10 800
2 電卓 事務用品 1500 2 3000
3 ファイル 文具 300 5 1500

処理前は4列、処理後は右端に売上列が加わって5列になりました。たとえばノートは120 × 3 = 360、電卓は1500 × 2 = 3000です。値だけでなく、計算に使った単価・数量と対応させて検算します。

商品名 処理前の単価 処理前の数量 処理後の売上
ノート 120 3 360
ペン 80 10 800
電卓 1500 2 3000
ファイル 300 5 1500

列を追加する複数の方法は、pandasで新しい列を追加する方法で詳しく説明しています。

売上1,000円以上の商品を抽出する

条件式df_sales["売上"] >= 1000を使い、条件を満たす行だけを残します。

high_sales = df_sales[df_sales["売上"] >= 1000]
high_sales
商品名 カテゴリ 単価 数量 売上
2 電卓 事務用品 1500 2 3000
3 ファイル 文具 300 5 1500

残ったのは電卓とファイルの2行です。左端のインデックスは元の23を維持しています。抽出後のインデックスが必ず0から始まるわけではありません。行ラベルの意味を残したい場合もあるため、無条件に振り直さないでください。

複数条件やquery()の使い方はpandas 条件抽出の基本、ラベル・位置指定はPandas locとilocの違いへ進みます。

売上の高い順に並べる

sort_values()は並べ替えたDataFrameを返します。結果をsorted_salesへ代入し、元のdf_salesと区別します。

sorted_sales = df_sales.sort_values("売上", ascending=False)
sorted_sales
商品名 カテゴリ 単価 数量 売上
2 電卓 事務用品 1500 2 3000
3 ファイル 文具 300 5 1500
1 ペン 文具 80 10 800
0 ノート 文具 120 3 360

売上が3000、1500、800、360の順になりました。sort_values()を実行しただけでは、元のdf_salesの行順は変わりません。並べ替え結果を後で使うなら、戻り値を変数へ保存します。

カテゴリ別に売上を集計する

最後に、カテゴリごとの売上合計を計算します。as_index=Falseを使い、結果を通常の2列のDataFrameとして表示します。

category_sales = (
    df_sales.groupby("カテゴリ", as_index=False)["売上"]
    .sum()
    .sort_values("売上", ascending=False)
)
category_sales
カテゴリ 売上
0 事務用品 3000
1 文具 2660

文具は360 + 800 + 1500 = 2660、事務用品は3000です。集計結果は、元の4商品がカテゴリ別の2行へまとまったことを確認します。集計方法の選び方はpandas groupby・aggの使い方で詳しく学べます。

やりたいこと 最初に使う方法 詳細記事
先頭の値を確認する head() pandas head()記事
構造・型・欠損を診断する info() pandas info()記事
行・列を指定する loc / iloc locとilocの比較記事
条件に合う行を残す ブール条件 pandas条件抽出記事
グループ別に集計する groupby() pandas groupby・agg記事
グラフを作る Matplotlib Matplotlib FigureとAxes記事

コードは動くが結果を誤解しやすい例

数字が文字列のままでもDataFrameは作れる

次のDataFrameはエラーなく作れますが、単価が文字列です。文字列と整数の掛け算は数値計算ではなく、文字の繰り返しになります。

bad_df = pd.DataFrame({
    "商品名": ["ノート", "ペン"],
    "単価": ["120", "80"],
    "数量": [3, 10],
})

bad_df["誤った売上"] = bad_df["単価"] * bad_df["数量"]
bad_df
商品名 単価 数量 誤った売上
0 ノート 120 3 120120120
1 ペン 80 10 80808080808080808080

ノートの結果が360ではなく120120120になっています。コードが止まらなくても、結果は売上として誤りです。dtypesと元の値を確認し、数値へ変換してから計算します。

bad_df["単価"] = pd.to_numeric(bad_df["単価"], errors="raise")
bad_df["売上"] = bad_df["単価"] * bad_df["数量"]
bad_df[["商品名", "単価", "数量", "売上"]]
商品名 単価 数量 売上
0 ノート 120 3 360
1 ペン 80 10 800

修正後はノートが360、ペンが800になりました。自分のデータに変換できない値が混ざる場合は、pandas to_numeric()の使い方errorsの選び方と変換失敗の確認方法を確認してください。

抽出・並べ替えは元データを自動変更しない

df_sales[条件]sort_values()は結果を返します。結果を変数へ代入せず、元のDataFrameも変わったと思い込むと、次のセルで古い行や行順を使うことになります。処理後にshape・列名・先頭行を再表示し、どの変数を使っているか確認します。

DataFrame作成時のエラーを確認して修正する

NameError: name 'pd' is not defined

現象pd.DataFrame(data)NameErrorが出ます。
原因import pandas as pdを実行していないか、Colabの再接続後にimportセルが未実行です。
確認方法:上のimportセルに実行済み番号があるか確認します。
修正方法import pandas as pdから順番に再実行します。
修正後の確認pd.__name__pandasとなり、DataFrameが表示されることを確認します。

ValueError: All arrays must be of the same length

現象:列単位の辞書からDataFrameを作るとValueErrorが出ます。
原因:辞書に入れたリストの要素数がそろっていません。
確認方法:列名と要素数を表示します。

uneven_data = {
    "商品名": ["ノート", "ペン", "電卓"],
    "単価": [120, 80],
}

{column: len(values) for column, values in uneven_data.items()}
{'商品名': 3, '単価': 2}

商品名は3件、単価は2件です。修正方法は、抜けた値の意味を確認し、誤って省略した値を追加するか、行単位の辞書のリストにして欠損を明示することです。意味を確認せず0を足してはいけません。修正後はshapeと表示結果を再確認します。

fixed_records = [
    {"商品名": "ノート", "単価": 120},
    {"商品名": "ペン", "単価": 80},
    {"商品名": "電卓", "単価": None},
]

fixed_df = pd.DataFrame(fixed_records)
fixed_df
商品名 単価
0 ノート 120.0
1 ペン 80.0
2 電卓 NaN

3行のDataFrameを作成でき、未確認の単価は欠損値NaNとして明示されました。欠損を埋めるか削除するかはデータの意味で判断します。確認はPandas isnull()で欠損値を確認する方法、補完はpandas fillna()の使い方へ進みます。

KeyErrorで列を選べない

現象:存在するはずの列をdf["商品名"]で選ぶとKeyErrorが出ます。
原因:列名の打ち間違い、前後空白、大文字・小文字の違いが考えられます。
確認方法:推測せず、df.columns.tolist()で実際の列名を確認します。
修正方法:指定を実在する列名へ直します。前後空白が原因なら、データの仕様を確認したうえでdf.columns = df.columns.str.strip()を使います。
修正後の確認:列名一覧を再表示し、目的の列だけが選べることを確認します。

自分のデータへ置き換えるときのチェックリスト

  • 辞書の各列で要素数がそろっているか
  • 行単位と列単位を取り違えていないか
  • shapeが想定した行数・列数か
  • columnsに空白や表記違いがないか
  • head()で値と列の対応が正しいか
  • 数値列や日付列が文字列になっていないか
  • info()で欠損していない件数を確認したか
  • 抽出後の行数とインデックスを確認したか
  • 並べ替えや集計の結果を新しい変数へ保存したか
  • 集計値を元データの一部から手計算して検算したか

行を追加する古い例でDataFrame.append()を見かけることがありますが、現在のPandasでは削除されています。行方向の結合にはpd.concat()を使います。詳しくはpandas concat()の使い方を参照してください。

DataFrameから次の分析へ進む

DataFrameを作った後は、いきなり複雑な分析へ進まず、次の順序で確認すると安全です。

  1. head()info()describe()で内容、型、欠損、分布を確認する
  2. 必要ならto_numeric()to_datetime()で型を直す
  3. isnull()で欠損を確認し、意味に応じて補完・削除を判断する
  4. lociloc・条件式で必要な行と列を抽出する
  5. groupby()等で集計する
  6. Matplotlibで可視化して傾向を確認する

この記事のcategory_salesは、そのままカテゴリ別の棒グラフへつなげられます。グラフ作成の土台はMatplotlib入門:FigureとAxesで確認できます。

まとめ

  • DataFrameは、複数列を持つ表形式データを扱う2次元のデータ構造です。
  • 列単位のデータは辞書、行単位のデータは辞書のリスト、既存ファイルは読み込み関数を選びます。
  • 作成後はshapecolumnsdtypeshead()info()で、行数・列名・型・欠損・値を確認します。
  • 1列をSeriesとして扱うならdf["列名"]、DataFrameを保つならdf[["列名"]]を使います。
  • 列追加・抽出・並べ替え・集計の後も、行数・値・順序・合計を検算します。
  • エラー時は、import、各列の長さ、実際の列名、データ型を順に確認します。

DataFrameの基本は、表を作ることだけではありません。出力を読み、正しいか判断し、目的に合う次の処理を選ぶことまでが一連の操作です。

関連記事

▲ ページトップへ戻る

DataFrameとSeriesはどう使い分けますか?

複数の列を持つ表として処理するならDataFrame、1列だけを計算・集計するならSeriesが基本です。1列でも表形式を保つ必要がある場合はdf[["列名"]]を使います。

辞書と辞書のリストでは、どちらからDataFrameを作ればよいですか?

値が列ごとにまとまっているなら辞書、1件分の値が行ごとにまとまっているなら辞書のリストが自然です。完成する表だけでなく、元データの形に合わせて選びます。

df["列名"]とdf[["列名"]]は何が違いますか?

前者は1次元のSeries、後者は2次元のDataFrameを返します。後続処理が求める型に合わせて選びます。

All arrays must be of the same lengthはどう直しますか?

辞書の各リストの要素数を確認します。入力漏れを直すか、行単位の辞書のリストを使って未確認値を欠損として明示し、作成後にshapeと内容を再確認します。

DataFrameを作った後、最初に何を確認すればよいですか?

shapecolumnsdtypeshead()info()を使い、行数・列名・型・先頭値・欠損していない件数を確認します。

行を追加するときにappend()を使ってもよいですか?

DataFrame.append()は現在のPandasでは削除されています。行方向にDataFrameをつなぐ場合はpd.concat()を使ってください。

コメント

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