Pandasを学び始めると、最初に登場するのがDataFrame(データフレーム)です。しかし、pd.DataFrame()で表を作れても、「辞書とリストのどちらを使うのか」「表示された表のどこを確認するのか」「次に何をすればよいのか」で迷いやすいものです。
この記事では、Google Colabで小さな売上データを作り、作成→確認→列選択→列追加→条件抽出→並べ替え→集計までを同じDataFrameで実行します。コードを動かすだけでなく、出力の行・列・型を読み、想定外の結果を自分で確認する方法まで身につけます。
この記事でわかること
- DataFrameの行・列・インデックスの意味
- 元データの形に合うDataFrameの作り方
- 作成後に
shape・columns・dtypes・head()・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行になります。左端の0〜3はインデックスです。通常のデータ列ではなく、行を識別するラベルとして使われます。
最初に見るのは、列名が「商品名・カテゴリ・単価・数量」になっているか、4行すべてが表示されているか、値が意図した列に入っているかです。
DataFrameの行・列・インデックスを確認する
図解:DataFrameのどこが行・列・インデックスか
| インデックス(行ラベル)↓/列名→ | 商品名 | カテゴリ | 単価 | 数量 |
|---|---|---|---|---|
| 0 | ノート | 文具 | 120 | 3 |
| 1 | ペン | 文具 | 80 | 10 |
上端の「商品名・カテゴリ・単価・数量」が列名、左端の0・1がインデックス、横方向の1組が行です。たとえば、インデックス0と「単価」が交差するセルの値は120です。
| 要素 | このDataFrameでの例 | 意味 |
|---|---|---|
| 行 | 0〜3の4行 |
1件分のデータ |
| 列 | 商品名、カテゴリ、単価、数量 | 同じ種類の値のまとまり |
| インデックス | 0、1、2、3 |
行を識別するラベル |
| セル | 商品名列の「ノート」など | 行と列が交差する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列」と読みます。columnsとindexも、作成前の想定と一致していることを確認します。
辞書のリストから作る場合との違い
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項目を確認します。
shape:想定した行数と列数かcolumns:列名の空白や表記違いがないかdtypes:数値や日付が適切な型かhead():先頭の値と列の対応が正しいか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 Countが4 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行です。左端のインデックスは元の2と3を維持しています。抽出後のインデックスが必ず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を作った後は、いきなり複雑な分析へ進まず、次の順序で確認すると安全です。
head()・info()・describe()で内容、型、欠損、分布を確認する- 必要なら
to_numeric()・to_datetime()で型を直す isnull()で欠損を確認し、意味に応じて補完・削除を判断するloc・iloc・条件式で必要な行と列を抽出するgroupby()等で集計する- Matplotlibで可視化して傾向を確認する
この記事のcategory_salesは、そのままカテゴリ別の棒グラフへつなげられます。グラフ作成の土台はMatplotlib入門:FigureとAxesで確認できます。
まとめ
- DataFrameは、複数列を持つ表形式データを扱う2次元のデータ構造です。
- 列単位のデータは辞書、行単位のデータは辞書のリスト、既存ファイルは読み込み関数を選びます。
- 作成後は
shape・columns・dtypes・head()・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を作った後、最初に何を確認すればよいですか?
shape、columns、dtypes、head()、info()を使い、行数・列名・型・先頭値・欠損していない件数を確認します。
行を追加するときにappend()を使ってもよいですか?
DataFrame.append()は現在のPandasでは削除されています。行方向にDataFrameをつなぐ場合はpd.concat()を使ってください。
コメント