CSVを読み込んで前処理をしていると、次のような場面がよく出てきます。
- 点数から「合格」「再確認」の列を作りたい
- 購入金額から「通常顧客」「見込み顧客」「重点顧客」のような区分を作りたい
- 複数の列を見て、1行ずつ判定したい
- 自分で作った関数を、DataFrameの列や行にまとめて使いたい
このようなときに使えるのが、Pandasの apply() です。
ただし、apply() は便利な一方で、何でも apply() で書けばよいわけではありません。 1列の値を対応表で変換するだけなら map()、値の置換なら replace()、型を変えるだけなら astype() や to_datetime() の方がわかりやすいこともあります。
この記事では、apply() を「何となく使う」のではなく、どの場面で使うべきか、axis=1 は何を意味するのか、lambda と自作関数をどう使い分けるかを、初心者向けに順番に解説します。
この記事を読むと、apply() の書き方を覚えるだけでなく、「map() で十分な場面」「apply(axis=1) を使うべき場面」「lambda ではなく自作関数に分けた方がよい場面」を判断できるようになります。
そのため、CSV読み込み後の前処理で、列を整えたり、複数列から判定列を作ったり、集計しやすいデータに変換したりする流れが理解しやすくなります。
- この記事でわかること
- データ分析の流れの中でのapply()の位置づけ
- 先に結論:apply()は「関数を列や行に適用する」ときに使う
- サンプルデータを用意する
- 1. Series.apply()で1列に処理を適用する
- 2. 自作関数をapply()に渡す
- 3. map()との違い:対応表があるならmap()が読みやすい
- 4. replace()・astype()・np.where()との使い分け
- 5. np.where()との違い:2択だけならnp.where()も使える
- 6. DataFrame.apply()とaxis=0・axis=1の違い
- 7. apply(axis=1)で複数列を見て新しい列を作る
- 8. 処理前→処理後で変化を確認する
- 9. 購入金額と年齢から顧客区分を作る
- 10. apply()の結果が反映されないように見える理由
- 11. 欠損値があるときの注意点
- 12. apply()でよくあるミス
- 13. apply()は遅い?初心者が知っておきたい範囲
- まとめ
- 次に読みたい関連記事
この記事でわかること
この記事では、次の内容を扱います。
apply()がどんな場面で役立つかSeries.apply()とDataFrame.apply()の違いlambdaを使った基本的な書き方axis=0とaxis=1の違い- 複数列を使って新しい列を作る方法
apply()、map()、replace()、astype()、np.where()の使い分けapply()でよくあるミスと注意点apply()で作った列を、集計や可視化の前処理につなげる考え方
この記事のゴールは、apply() を、map() や replace() では足りないときに使う「関数適用の道具」として理解し、1列処理・行ごとの処理・新しい列作成を安全に使い分けられるようになることです。
データ分析の流れの中でのapply()の位置づけ
apply() は、DataFrameを読み込んだ直後に最初に使う機能というより、データを確認したあとに、分析しやすい形へ整える前処理でよく使います。
たとえば、次のような流れです。
head()、info()、describe()でデータの中身を確認するrename()、replace()、astype()、to_datetime()などで列名・値・型を整えるmap()やapply()で、分析しやすい列を作るvalue_counts()やgroupby()で集計する- Matplotlibで可視化する
つまり apply() は、前処理から集計・可視化へ進むために、必要な列を作る道具として考えるとわかりやすいです。
先に結論:apply()は「関数を列や行に適用する」ときに使う
apply() は、Pandasの列や行に対して、同じ処理をまとめて適用するためのメソッドです。
たとえば、次のような処理に向いています。
- 1列の値をもとに、判定結果を作る
- 複数列を見て、1行ごとに区分を作る
- 自作関数をDataFrameに適用する
- 短い処理を
lambdaで書く
特に、次のように判断すると迷いにくくなります。
1列の対応表変換なら
map()、値の置換ならreplace()、型変換ならastype()、複数列を見て1行ずつ判定するならapply(axis=1)を検討します。
apply() は、単純な置換や型変換よりも、自分で作った判定ルールや関数を列・行に適用したいときに向いています。
一方で、apply() は万能ではありません。 まずは、次の表で使い分けを押さえておきましょう。
| やりたいこと | まず検討したい方法 | 理由 |
|---|---|---|
| 1列を辞書で変換したい | map() |
対応表がある変換は読みやすい |
| 値を別の値に置き換えたい | replace() |
表記ゆれ修正や値の置換に向く |
| 文字列を数値型に変えたい | astype() |
型変換の目的が明確 |
| 日付文字列を日付型にしたい | to_datetime() |
日付変換に特化している |
| 単純な条件で2択に分けたい | np.where() |
短い条件分岐を簡潔に書ける |
| 関数を列に適用したい | apply() |
計算や判定を関数として使える |
| 複数列を見て1行ずつ判定したい | apply(axis=1) |
行ごとの処理を書きやすい |
なお、この記事では「新しい列を作る方法全体」ではなく、apply()を使って関数の結果を列として追加する場面に絞って解説します。 df["新しい列"] = ... や assign() など、列追加そのものの基本は、別記事の「pandasで新しい列を追加する方法」で整理すると理解しやすいです。
初心者のうちは、単純な処理まで何でも apply() にしないことが大切です。
💡 ポイント apply() は便利ですが、何でも apply() で書く必要はありません。まずは map()・replace()・astype() で書けないかを確認し、それでも関数を適用したいときに apply() を使うと整理しやすくなります。
apply() は、「ほかの方法では書きにくい処理を、関数として適用したいとき」に使うと考えると整理しやすくなります。
サンプルデータを用意する
この記事では、Google Colabでそのまま試せるように、小さなサンプルDataFrameを使います。
学習データと購買データが混ざったような例にして、apply() で「合否」「税込金額」「顧客区分」などを作っていきます。
import pandas as pd
df = pd.DataFrame({
"名前": ["田中", "佐藤", "鈴木", "高橋", "伊藤", "渡辺"],
"年齢": [22, 35, 41, 29, 52, 38],
"点数": [82, 59, 74, 91, 66, 88],
"出席率": [0.95, 0.70, 0.82, 0.98, 0.60, 0.90],
"購入金額": [12000, 45000, 28000, 62000, 8000, 37000],
"地域": ["東京", "大阪", "東京", "福岡", "札幌", "大阪"]
})
df
| 名前 | 年齢 | 点数 | 出席率 | 購入金額 | 地域 | |
|---|---|---|---|---|---|---|
| 0 | 田中 | 22 | 82 | 0.95 | 12000 | 東京 |
| 1 | 佐藤 | 35 | 59 | 0.7 | 45000 | 大阪 |
| 2 | 鈴木 | 41 | 74 | 0.82 | 28000 | 東京 |
| 3 | 高橋 | 29 | 91 | 0.98 | 62000 | 福岡 |
| 4 | 伊藤 | 52 | 66 | 0.6 | 8000 | 札幌 |
| 5 | 渡辺 | 38 | 88 | 0.9 | 37000 | 大阪 |
1. Series.apply()で1列に処理を適用する
まずは、1列だけに apply() を使う基本形です。
1列に対して使う場合は、df["列名"].apply(関数) のように書きます。 これは Series.apply() と呼ばれる使い方です。
次の例では、点数 列をもとに、80点以上なら「合格」、それ以外なら「再確認」とする列を作ります。
df["判定"] = df["点数"].apply(lambda x: "合格" if x >= 80 else "再確認")
df[["名前", "点数", "判定"]]
| 名前 | 点数 | 判定 | |
|---|---|---|---|
| 0 | 田中 | 82 | 合格 |
| 1 | 佐藤 | 59 | 再確認 |
| 2 | 鈴木 | 74 | 再確認 |
| 3 | 高橋 | 91 | 合格 |
| 4 | 伊藤 | 66 | 再確認 |
| 5 | 渡辺 | 88 | 合格 |
lambda x: は、「列の値を1つずつ受け取って処理する短い関数」と考えるとわかりやすいです。
上の例では、点数 列の値が1つずつ x に入り、条件に応じて「合格」または「再確認」が返されます。
ただし、条件が長くなる場合は、lambda に無理やり詰め込まない方が読みやすくなります。 その場合は、次のように自作関数に分けるのがおすすめです。
2. 自作関数をapply()に渡す
apply() には、lambda だけでなく、自分で定義した関数も渡せます。
条件が2つ以上ある場合や、あとで読み返したい処理は、自作関数に分けると見通しがよくなります。
def score_label(score):
if score >= 80:
return "高得点"
elif score >= 70:
return "標準"
else:
return "要復習"
df["点数区分"] = df["点数"].apply(score_label)
df[["名前", "点数", "点数区分"]]
| 名前 | 点数 | 点数区分 | |
|---|---|---|---|
| 0 | 田中 | 82 | 高得点 |
| 1 | 佐藤 | 59 | 要復習 |
| 2 | 鈴木 | 74 | 標準 |
| 3 | 高橋 | 91 | 高得点 |
| 4 | 伊藤 | 66 | 要復習 |
| 5 | 渡辺 | 88 | 高得点 |
このように、自作関数を使うと、処理の意味が見出しや本文と対応しやすくなります。
| 書き方 | 向いている場面 |
|---|---|
lambda |
1行で読める短い処理 |
| 自作関数 | 条件が複数ある処理 |
| 自作関数 | あとで読み返したい処理 |
| 自作関数 | ブログ記事やチーム共有で説明しやすくしたい処理 |
lambda は便利ですが、初心者向けの記事では、複雑な条件ほど自作関数の方が理解しやすいことが多いです。
3. map()との違い:対応表があるならmap()が読みやすい
apply() とよく比較されるのが map() です。
map() は、1列の値を辞書などの対応表で変換するときに向いています。 たとえば、地域名からエリア名を作るような処理です。
area_map = {
"東京": "関東",
"大阪": "関西",
"福岡": "九州",
"札幌": "北海道"
}
df["エリア"] = df["地域"].map(area_map)
df[["名前", "地域", "エリア"]]
| 名前 | 地域 | エリア | |
|---|---|---|---|
| 0 | 田中 | 東京 | 関東 |
| 1 | 佐藤 | 大阪 | 関西 |
| 2 | 鈴木 | 東京 | 関東 |
| 3 | 高橋 | 福岡 | 九州 |
| 4 | 伊藤 | 札幌 | 北海道 |
| 5 | 渡辺 | 大阪 | 関西 |
このように、「東京なら関東、大阪なら関西」のように対応表がはっきりしている変換では、apply() より map() の方が読みやすくなります。
一方で、次のように条件や計算が入る場合は、apply() の方が自然に書けることがあります。
- 点数に応じてラベルを分ける
- 購入金額に応じてランクを作る
- 複数列を見て判定する
apply() と map() の違いは、次のように考えると整理しやすいです。
| 比較 | 向いている処理 |
|---|---|
map() |
1列の値を対応表で変換する |
apply() |
1列に関数を適用する |
apply(axis=1) |
複数列を見て1行ずつ判定する |
辞書で値を変換する基本は、別記事の「pandas map()の使い方」で詳しく学ぶと理解しやすいです。
4. replace()・astype()・np.where()との使い分け
apply() は便利ですが、値の置換や型変換まで全部 apply() で書く必要はありません。
次の表のように、目的に合ったメソッドを選ぶと、コードが読みやすくなります。
| やりたいこと | 例 | 向いている方法 |
|---|---|---|
| 表記ゆれを直す | "Tokyo" を "東京" にする |
replace() |
| 型を変える | 文字列の数値を int にする |
astype() |
| 日付に変換する | "2026-05-04" を日付型にする |
to_datetime() |
| 2択の条件分岐 | 80点以上なら合格 | np.where() または apply() |
| 複数条件で区分する | 点数と出席率を見て判定 | apply(axis=1) |
| 自作関数を使う | 独自ルールでランク付け | apply() |
ここで大切なのは、apply() を「何でもできる道具」として使いすぎないことです。 処理の目的がはっきりしている場合は、専用のメソッドを優先すると、あとで読み返しやすくなります。
5. np.where()との違い:2択だけならnp.where()も使える
単純な2択の条件分岐なら、apply() だけでなく np.where() でも書けます。
たとえば、80点以上なら「合格」、それ以外なら「再確認」とするだけなら、次のように書けます。
import numpy as np
df["判定_npwhere"] = np.where(df["点数"] >= 80, "合格", "再確認")
df[["名前", "点数", "判定", "判定_npwhere"]]
| 名前 | 点数 | 判定 | 判定_npwhere | |
|---|---|---|---|---|
| 0 | 田中 | 82 | 合格 | 合格 |
| 1 | 佐藤 | 59 | 再確認 | 再確認 |
| 2 | 鈴木 | 74 | 再確認 | 再確認 |
| 3 | 高橋 | 91 | 合格 | 合格 |
| 4 | 伊藤 | 66 | 再確認 | 再確認 |
| 5 | 渡辺 | 88 | 合格 | 合格 |
np.where() は、条件が1つで結果が2択のときに短く書けます。
一方で、条件が複数ある場合や、処理の意味を関数名として残したい場合は、自作関数と apply() を組み合わせた方が読みやすくなります。
| 書き方 | 向いている場面 |
|---|---|
np.where() |
条件が1つで、結果が2択のとき |
apply() |
関数を使って処理したいとき |
apply(axis=1) |
複数列を見て1行ずつ判定したいとき |
この記事では、np.where() を深く扱いすぎず、apply() を使う判断材料として軽く押さえます。
6. DataFrame.apply()とaxis=0・axis=1の違い
ここからは、DataFrame.apply() を見ていきます。
DataFrame.apply() では、axis の指定が重要です。
| 指定 | 意味 | 初心者向けの考え方 |
|---|---|---|
axis=0 |
列ごとに処理する | 各列を縦に見て処理する |
axis=1 |
行ごとに処理する | 1行ずつ見て処理する |
特に axis=1 は、初心者がつまずきやすいポイントです。 「横方向に処理する」と覚えるより、1行ずつ処理すると考える方がわかりやすいです。
axisのイメージ
axis は、DataFrameをどの向きで処理するかを指定する引数です。 最初は少し混乱しやすいので、次のようにイメージすると整理しやすくなります。
| 指定 | 見る方向 | イメージ | よく使う場面 |
|---|---|---|---|
axis=0 |
列ごと | 各列を上から下に見る | 各列の平均・合計を出す |
axis=1 |
行ごと | 各行を左から右に見る | 複数列を見て1行ずつ判定する |
たとえば、axis=0 は「国語列」「数学列」のように列単位で処理します。 一方、axis=1 は「1人目の国語と数学」「2人目の国語と数学」のように、1行分の複数列をまとめて見ます。
つまり、複数列を使って新しい列を作りたいときは apply(axis=1) が候補になります。
まずは、小さな点数表で確認します。
scores = pd.DataFrame({
"国語": [80, 60, 90],
"数学": [70, 75, 85]
})
scores
| 国語 | 数学 | |
|---|---|---|
| 0 | 80 | 70 |
| 1 | 60 | 75 |
| 2 | 90 | 85 |
axis=0 を指定すると、列ごとに処理します。 次の例では、各科目の平均点を計算しています。
scores.apply(lambda col: col.mean(), axis=0)
| 国語 | 76.66666666666667 |
| 数学 | 76.66666666666667 |
一方、axis=1 を指定すると、行ごとに処理します。 次の例では、各人の平均点を計算しています。
scores.apply(lambda row: row.mean(), axis=1)
| 0 | 75.0 |
| 1 | 67.5 |
| 2 | 87.5 |
この違いを理解すると、apply(axis=1) がなぜ複数列を使う処理で登場するのかが見えてきます。
- 列ごとに処理したい →
axis=0 - 1行ずつ複数列を見たい →
axis=1
実務では、axis=1 は「年齢と購入金額を見て顧客区分を作る」「点数と出席率を見てフォロー対象を判定する」ような場面で使います。
7. apply(axis=1)で複数列を見て新しい列を作る
次に、複数列を見て1行ずつ判定する例です。
ここでは、点数 と 出席率 を見て、学習フォローの区分を作ります。
- 点数が80点以上、かつ出席率が0.8以上なら「順調」
- 点数が70点未満、または出席率が0.75未満なら「要フォロー」
- それ以外は「通常」
このように、複数列を見て判定したい場合は、apply(axis=1) が候補になります。
def follow_status(row):
if row["点数"] >= 80 and row["出席率"] >= 0.8:
return "順調"
elif row["点数"] < 70 or row["出席率"] < 0.75:
return "要フォロー"
else:
return "通常"
df["学習フォロー"] = df.apply(follow_status, axis=1)
df[["名前", "点数", "出席率", "学習フォロー"]]
| 名前 | 点数 | 出席率 | 学習フォロー | |
|---|---|---|---|---|
| 0 | 田中 | 82 | 0.95 | 順調 |
| 1 | 佐藤 | 59 | 0.7 | 要フォロー |
| 2 | 鈴木 | 74 | 0.82 | 通常 |
| 3 | 高橋 | 91 | 0.98 | 順調 |
| 4 | 伊藤 | 66 | 0.6 | 要フォロー |
| 5 | 渡辺 | 88 | 0.9 | 順調 |
この例では、関数の引数 row に、DataFrameの1行分のデータが入ります。 そのため、row["点数"] や row["出席率"] のように、同じ行の複数列を参照できます。
これが、Series.apply() と DataFrame.apply(axis=1) の大きな違いです。
| 使い方 | 処理対象 | 例 |
|---|---|---|
df["点数"].apply(...) |
1列の値 | 点数から合否を作る |
df.apply(..., axis=1) |
1行分のデータ | 点数と出席率を見て判定する |
8. 処理前→処理後で変化を確認する
apply() で新しい列を作るときは、処理前と処理後を確認すると理解しやすくなります。
今回の例では、もともと 点数 と 出席率 だけがありました。 そこに、apply(axis=1) で 学習フォロー 列を追加しました。
| 処理前 | 処理内容 | 処理後 |
|---|---|---|
点数、出席率 |
2つの列を1行ずつ見て判定 | 学習フォロー 列を追加 |
| 82、0.95 | 条件を満たす | 順調 |
| 59、0.70 | 点数または出席率が低い | 要フォロー |
apply() の結果を新しい列として保存すると、あとで value_counts() や groupby() にもつなげやすくなります。
df["学習フォロー"].value_counts()
| count | |
|---|---|
| 順調 | 3 |
| 要フォロー | 2 |
| 通常 | 1 |
このように、apply() は列を作って終わりではありません。 作成した列を使って件数を数えたり、グループ別に集計したりすることで、分析に進みやすくなります。
9. 購入金額と年齢から顧客区分を作る
もう1つ、前処理らしい例を見てみましょう。
ここでは、購入金額 と 年齢 を使って、顧客区分を作ります。
- 購入金額が50,000円以上、かつ年齢が30歳以上なら「重点顧客」
- 購入金額が30,000円以上なら「見込み顧客」
- それ以外は「通常顧客」
このような独自ルールは、replace() や astype() では書きにくいため、apply(axis=1) が向いています。
def customer_type(row):
if row["購入金額"] >= 50000 and row["年齢"] >= 30:
return "重点顧客"
elif row["購入金額"] >= 30000:
return "見込み顧客"
else:
return "通常顧客"
df["顧客区分"] = df.apply(customer_type, axis=1)
df[["名前", "年齢", "購入金額", "顧客区分"]]
| 名前 | 年齢 | 購入金額 | 顧客区分 | |
|---|---|---|---|---|
| 0 | 田中 | 22 | 12000 | 通常顧客 |
| 1 | 佐藤 | 35 | 45000 | 見込み顧客 |
| 2 | 鈴木 | 41 | 28000 | 通常顧客 |
| 3 | 高橋 | 29 | 62000 | 見込み顧客 |
| 4 | 伊藤 | 52 | 8000 | 通常顧客 |
| 5 | 渡辺 | 38 | 37000 | 見込み顧客 |
作成した 顧客区分 は、そのまま集計に使えます。
df.groupby("顧客区分")["購入金額"].mean()
| 購入金額 | |
|---|---|
| 見込み顧客 | 48000.0 |
| 通常顧客 | 16000.0 |
この流れは、実際のデータ分析でもよく使います。
- 元データを確認する
- 必要なルールを決める
apply()で区分列を作るvalue_counts()やgroupby()で集計する- 必要に応じてグラフ化する
apply() は、前処理と集計をつなぐ中間の役割を持っています。
10. apply()の結果が反映されないように見える理由
初心者がよく迷うのが、apply() を実行したのにDataFrameが変わっていないように見えるケースです。
apply() は、処理結果を返します。 新しい列として残したい場合は、結果を df["新しい列"] に代入する必要があります。
⚠️ 注意 apply() の結果を新しい列として残したい場合は、必ず df["新しい列"] = ... の形で代入します。結果が表示されただけでは、元のDataFrameに保存されたわけではありません。
まずは、代入しない例を見てみます。
df["購入金額"].apply(lambda x: int(x * 1.1))
| 購入金額 | |
|---|---|
| 0 | 13200 |
| 1 | 49500 |
| 2 | 30800 |
| 3 | 68200 |
| 4 | 8800 |
| 5 | 40700 |
上のコードを実行すると、税込金額の結果は表示されます。 しかし、これだけでは df に新しい列は追加されません。
新しい列として保存したい場合は、次のように代入します。
df["税込金額"] = df["購入金額"].apply(lambda x: int(x * 1.1))
df[["名前", "購入金額", "税込金額"]]
| 名前 | 購入金額 | 税込金額 | |
|---|---|---|---|
| 0 | 田中 | 12000 | 13200 |
| 1 | 佐藤 | 45000 | 49500 |
| 2 | 鈴木 | 28000 | 30800 |
| 3 | 高橋 | 62000 | 68200 |
| 4 | 伊藤 | 8000 | 8800 |
| 5 | 渡辺 | 37000 | 40700 |
このように、apply() の結果をあとで使いたい場合は、必ず列に保存しましょう。
| 状況 | 書き方 |
|---|---|
| 結果を一時的に確認したい | df["列"].apply(...) |
| 新しい列として残したい | df["新しい列"] = df["列"].apply(...) |
なお、税込金額のような単純な四則演算だけなら、実務では apply() を使わずに列同士の計算で書く方がシンプルな場合もあります。
df["税込金額_直接計算"] = (df["購入金額"] * 1.1).astype(int)
df[["名前", "購入金額", "税込金額", "税込金額_直接計算"]]
| 名前 | 購入金額 | 税込金額 | 税込金額_直接計算 | |
|---|---|---|---|---|
| 0 | 田中 | 12000 | 13200 | 13200 |
| 1 | 佐藤 | 45000 | 49500 | 49500 |
| 2 | 鈴木 | 28000 | 30800 | 30800 |
| 3 | 高橋 | 62000 | 68200 | 68200 |
| 4 | 伊藤 | 8000 | 8800 | 8800 |
| 5 | 渡辺 | 37000 | 40700 | 40700 |
この例のように、単純な計算なら apply() より列同士の直接計算の方が読みやすいことがあります。 apply() は便利ですが、常に最初の選択肢にする必要はありません。
11. 欠損値があるときの注意点
apply() では、欠損値がある列を処理するときにも注意が必要です。
たとえば、点数が未入力のデータがあるとします。 このような場合に、何も考えずに比較処理を書くと、意図しない結果になることがあります。
ここでは、点数が未入力の場合は「未確認」と返すようにします。
df_missing = pd.DataFrame({
"名前": ["田中", "佐藤", "鈴木"],
"点数": [82, None, 68]
})
def safe_score_label(score):
if pd.isna(score):
return "未確認"
elif score >= 80:
return "高得点"
elif score >= 70:
return "標準"
else:
return "要復習"
df_missing["点数区分"] = df_missing["点数"].apply(safe_score_label)
df_missing
| 名前 | 点数 | 点数区分 | |
|---|---|---|---|
| 0 | 田中 | 82.0 | 高得点 |
| 1 | 佐藤 | nan | 未確認 |
| 2 | 鈴木 | 68.0 | 要復習 |
欠損値を含む列では、pd.isna() で未入力を確認してから処理すると安全です。
ただし、欠損値をどう扱うべきかはデータの意味によって変わります。 単純に0で埋めればよいとは限らないため、欠損値処理は fillna() や dropna() の考え方と合わせて整理するとよいです。
12. apply()でよくあるミス
ここでは、初心者がつまずきやすいポイントを整理します。
ミス1:axis=1を付け忘れる
複数列を見て1行ずつ処理したいのに、axis=1 を付け忘れると、想定通りに動かないことがあります。
# 複数列を1行ずつ見たいなら axis=1 が必要
df.apply(customer_type, axis=1)
axis=1 は、「1行ずつ処理する」と覚えると迷いにくいです。
ミス2:apply()の結果を代入していない
次のように書くと、結果は表示されますが、DataFrameには保存されません。
df["購入金額"].apply(lambda x: int(x * 1.1))
列として残したい場合は、次のように代入します。
df["税込金額"] = df["購入金額"].apply(lambda x: int(x * 1.1))
ミス3:lambdaに条件を書きすぎる
lambda は短い処理には便利ですが、条件が長くなると読みにくくなります。
# 読みにくくなりやすい例
df["区分"] = df["点数"].apply(lambda x: "高得点" if x >= 80 else "標準" if x >= 70 else "要復習")
このような場合は、自作関数に分ける方が読みやすくなります。
ミス4:apply()を何でも使ってしまう
apply() は便利ですが、単純な計算や型変換まで apply() にすると、かえって読みづらくなることがあります。
- 単純な計算 → 列同士の計算
- 辞書で変換 →
map() - 値の置換 →
replace() - 型変換 →
astype()やto_datetime()
このように、処理の目的に合う方法を選びましょう。
13. apply()は遅い?初心者が知っておきたい範囲
apply() は便利ですが、大量データでは処理が遅くなることがあります。
ただし、初心者の段階では、最初から速度ばかり気にしすぎる必要はありません。 まずは、次の順番で考えるとよいです。
- 処理の意味が自分で説明できるか
map()、replace()、astype()など、より目的に合う方法がないか- 単純な計算なら、列同士の計算で書けないか
- それでも関数適用が必要なら
apply()を使う
たとえば、税込金額のように df["購入金額"] * 1.1 で書ける処理は、apply() よりも列同士の計算で書く方がシンプルです。 まずは「列同士の計算で書けないか」を確認し、それでも自作関数が必要なときに apply() を使うと整理しやすくなります。
巨大データの高速化、NumPyを使った最適化、groupby.apply() の高度な使い方は、この記事では深入りしません。 まずは、apply() の基本と使いどころを理解することを優先しましょう。
まとめ
この記事では、pandas apply() の使い方を、初心者向けに解説しました。
大切なポイントは次の通りです。
apply()は、関数を列や行にまとめて適用したいときに使う- 1列だけに使う場合は
df["列"].apply(...) - 複数列を見て1行ずつ処理したい場合は
df.apply(..., axis=1) axis=1は「1行ずつ処理する」と考えるとわかりやすい- 短い処理は
lambda、複雑な条件は自作関数に分けると読みやすい - 1列の対応表変換なら
map()、値の置換ならreplace()、型変換ならastype()を優先する - 単純な2択の条件分岐なら
np.where()、複数条件や自作ルールならapply()を検討する apply()の結果を列として残したい場合は、df["新しい列"] = ...のように代入するapply()で作った列は、value_counts()やgroupby()による集計につなげやすい
apply() は、Pandasの前処理でよく使う便利な道具です。 ただし、この記事の中心は「列追加そのもの」ではなく、関数の結果を列や行に適用する考え方です。 ただし、何でも apply() にするのではなく、「関数を適用する必要があるか」「ほかのメソッドの方が自然ではないか」を考えながら使うと、読みやすいコードになります。
次に読みたい関連記事
この記事とあわせて読むと、Pandasの前処理から集計までの流れが理解しやすくなります。
- Pandas DataFrame入門|作り方・基本操作をわかりやすく解説
- pandas map()の使い方|辞書で値を変換・新しい列を作る方法を初心者向けに解説
- pandasで新しい列を追加する方法|df[‘列名’]・assign・条件付き列追加を初心者向けに解説
- pandas replace()の使い方|値の置換・表記ゆれ・欠損値変換を解説
- pandas astype()の使い方|文字列・数値への型変換とエラー対処を初心者向けに解説
- pandas 条件抽出(filtering)入門|AND/OR・query関数・複数条件の指定方法
- pandas fillna()の使い方|欠損値を0・平均値・中央値・最頻値で埋める方法を初心者向けに解説
- pandas value_counts()の使い方|件数集計・割合表示・欠損値の数え方を解説
- Pandas groupby×aggの使い方|基本の集計とaggの書き方を例で解説
pandas apply()は何に使いますか?
apply() は、Pandasの列や行に関数をまとめて適用したいときに使います。 たとえば、点数から判定列を作る、購入金額から顧客区分を作る、複数列を見て1行ずつ判定する、といった場面で役立ちます。
apply()とmap()の違いは何ですか?
map() は、主に1列の値を対応表で変換するときに使います。 一方、apply() は、関数を使って値を加工したいときや、複数列を見て行ごとに判定したいときに使います。
apply(axis=1)とはどういう意味ですか?
apply(axis=1) は、DataFrameを1行ずつ処理する指定です。 複数列を見て新しい列を作りたいときに使います。たとえば、点数 と 出席率 を見て「順調」「要フォロー」を判定するような場面です。
lambdaを使わずにapply()は使えますか?
使えます。 lambda の代わりに、自分で定義した関数を apply() に渡せます。条件が複数ある場合や、あとで読み返しやすくしたい場合は、自作関数に分けるのがおすすめです。
apply()で新しい列を作れますか?
作れます。 たとえば、df["新しい列"] = df["元の列"].apply(関数) のように書くと、処理結果を新しい列として保存できます。複数列を使う場合は、df["新しい列"] = df.apply(関数, axis=1) のように書きます。
apply()の結果が元のDataFrameに反映されないのはなぜですか?
apply() の結果を表示しただけでは、元のDataFrameには保存されません。 新しい列として残したい場合は、df["新しい列"] = ... のように代入する必要があります。
apply()とnp.where()はどちらを使えばよいですか?
単純な2択の条件分岐なら np.where() が簡潔です。たとえば、80点以上なら「合格」、それ以外なら「再確認」のような処理です。 一方で、条件が複数ある場合や、自作関数で処理を整理したい場合は apply() が向いています。初心者のうちは、短く書くことよりも、あとで読んで意味がわかることを優先して選ぶとよいです。
apply()が遅いと言われるのはなぜですか?
apply() は、行や値を1つずつ関数に渡して処理するため、大量データでは遅くなることがあります。 単純な計算なら列同士の計算、辞書変換なら map()、値の置換なら replace() のように、目的に合った方法を選ぶと読みやすさと効率の両方を保ちやすくなります。
applymap()やDataFrame.map()もこの記事で扱うべきですか?
この記事では、初心者がまず迷いやすい apply()、axis=1、lambda、map() との違いに絞って解説しています。 applymap() や DataFrame.map() は、DataFrame内の各要素に処理を適用する場面で使われますが、最初から広げると混乱しやすいため、この記事では深入りしません。
コメント