ExcelユーザーのためのPandas「locメソッド」ガイド
はじめに
「特定の条件に当てはまる行だけ更新したい...」
「複雑な条件でのデータ更新がうまくいかない...」
「データの一括置換はできるけど、一部だけを更新するのが難しい...」
Pythonでデータ分析を始めると、必ずぶつかる壁の一つが条件付きデータの更新です。
特にExcelから移行してきた方は、オートフィルやif文のような直感的な操作ができず、戸惑うことも多いのではないでしょうか。
今回は、pandasのlocメソッドによる条件付きデータ更新について、基礎から実践的なテクニックまで詳しく解説していきます。
データの準備
まずは、実践的なサンプルデータを用意しましょう。
import pandas as pd
import numpy as np
# 商品管理データの作成
data = {
'商品名': ['りんご', 'みかん', 'バナナ', 'いちご', 'メロン', 'ぶどう', 'キウイ', 'マンゴー'],
'価格': [100, 80, 120, 450, 800, 300, 150, 600],
'在庫': [50, 100, 30, 20, 15, 45, 60, 10],
'カテゴリ': ['果物', '果物', '果物', '果物', '果物', '果物', '果物', '果物'],
'産地': ['国内', '国内', '海外', '国内', '国内', '国内', '海外', '海外']
}
df = pd.DataFrame(data)
df
商品名 | 価格 | 在庫 | カテゴリ | 産地 | |
---|---|---|---|---|---|
0 | りんご | 100 | 50 | 果物 | 国内 |
1 | みかん | 80 | 100 | 果物 | 国内 |
2 | バナナ | 120 | 30 | 果物 | 海外 |
3 | いちご | 450 | 20 | 果物 | 国内 |
4 | メロン | 800 | 15 | 果物 | 国内 |
5 | ぶどう | 300 | 45 | 果物 | 国内 |
6 | キウイ | 150 | 60 | 果物 | 海外 |
7 | マンゴー | 600 | 10 | 果物 | 海外 |
条件付き更新の基本
locメソッドの基本構文
まずは、pandasのlocメソッドの基本的な構文について理解しておきましょう。
# 基本構文
df.loc[行の条件, 列の指定] = 更新する値
# 具体例:
df.loc[df['価格'] > 1000, '商品区分'] = '高額商品' # 単一列の更新
df.loc[df['在庫'] < 5, ['価格', '状態']] = [0, '品切れ'] # 複数列の更新
ここで重要なのは、locメソッドの[]
の中には2つの要素があるということです。
- 1つ目の要素:行の選択条件(どの行を更新するか)
- 2つ目の要素:列の指定(どの列を更新するか)
applyメソッドとlocの組み合わせ
より複雑な更新処理が必要な場合、locとapplyメソッドを組み合わせることができます。
# 基本構文
df.loc[行の条件, '更新する列'] = df[条件に合う行].apply(更新用の関数, axis=1)
# 具体例:
df.loc[df['在庫'] < 10, '価格'] = df[df['在庫'] < 10].apply(
lambda row: row['価格'] * 1.2 if row['産地'] == '海外' else row['価格'],
axis=1
)
この場合の処理の流れは以下のようになります。
-
df['在庫'] < 10
で対象となる行を選択 - 選択された行に対してapply関数を適用
- 関数の戻り値で該当する列を更新
シンプルな条件での更新
最も基本的な使い方から見ていきましょう。以下は価格が500円以上の商品を「高級フルーツ」カテゴリに変更する例です。
# 価格による条件付き更新
df.loc[df['価格'] >= 500, 'カテゴリ'] = '高級フルーツ'
df
商品名 | 価格 | 在庫 | カテゴリ | 産地 | |
---|---|---|---|---|---|
0 | りんご | 100 | 50 | 果物 | 国内 |
1 | みかん | 80 | 100 | 果物 | 国内 |
2 | バナナ | 120 | 30 | 果物 | 海外 |
3 | いちご | 450 | 20 | 果物 | 国内 |
4 | メロン | 800 | 15 | 高級フルーツ | 国内 |
5 | ぶどう | 300 | 45 | 果物 | 国内 |
6 | キウイ | 150 | 60 | 果物 | 海外 |
7 | マンゴー | 600 | 10 | 高級フルーツ | 海外 |
この操作は以下のような流れで処理されます。
-
df['価格'] >= 500
で条件に合う行を選択(TrueまたはFalseの配列が生成されます) - 選択された行の 'カテゴリ' 列を更新
- その他の行は変更されません
複数条件を組み合わせた更新
実務では、複数の条件を組み合わせて更新することが多くあります。
以下は、輸入品で在庫が少ない商品の価格を20%上げる例です。
# 複数条件による価格改定
df.loc[(df['産地'] == '海外') & (df['在庫'] < 30), '価格'] *= 1.2
# 結果を確認(変更された行を抽出)
df.loc[(df['産地'] == '海外') & (df['在庫'] < 30)]
df
商品名 | 価格 | 在庫 | カテゴリ | 産地 | |
---|---|---|---|---|---|
7 | マンゴー | 720 | 10 | 果物 | 海外 |
実践的な条件付き更新テクニック
1. 既存の値を利用した更新
在庫数に応じて価格を段階的に調整する例を見てみましょう。
# 在庫状況に応じた価格調整
def adjust_price_by_stock(row):
if row['在庫'] <= 10:
return row['価格'] * 1.3 # 品薄:30%値上げ
elif row['在庫'] <= 30:
return row['価格'] * 1.1 # やや品薄:10%値上げ
elif row['在庫'] >= 100:
return row['価格'] * 0.9 # 過剰在庫:10%値下げ
else:
return row['価格'] # 通常在庫:変更なし
# 価格の更新を実行
df.loc[:, '調整後価格'] = df.apply(adjust_price_by_stock, axis=1)
df
商品名 | 価格 | 在庫 | カテゴリ | 産地 | 調整後価格 | |
---|---|---|---|---|---|---|
0 | りんご | 100 | 50 | 果物 | 国内 | 100.0 |
1 | みかん | 80 | 100 | 果物 | 国内 | 72.0 |
2 | バナナ | 120 | 30 | 果物 | 海外 | 132.0 |
3 | いちご | 450 | 20 | 果物 | 国内 | 495.0 |
4 | メロン | 800 | 15 | 果物 | 国内 | 880.0 |
5 | ぶどう | 300 | 45 | 果物 | 国内 | 300.0 |
6 | キウイ | 150 | 60 | 果物 | 海外 | 150.0 |
7 | マンゴー | 600 | 10 | 果物 | 海外 | 780.0 |
2. 複数列の同時更新
同じ条件で複数の列を更新する場合もよくあります。
# 海外産の商品の価格と在庫情報を同時に更新
df.loc[df['産地'] == '海外', ['価格', '在庫']] = df.loc[df['産地'] == '海外'].apply(lambda row: pd.Series({
'価格': row['価格'] * 1.15, # 15%値上げ
'在庫': row['在庫'] - 5 # 在庫数を5減らす
}),
axis=1
)
df
商品名 | 価格 | 在庫 | カテゴリ | 産地 | |
---|---|---|---|---|---|
0 | りんご | 100.000 | 50 | 果物 | 国内 |
1 | みかん | 80.000 | 100 | 果物 | 国内 |
2 | バナナ | 158.700 | 20 | 果物 | 海外 |
3 | いちご | 450.000 | 20 | 果物 | 国内 |
4 | メロン | 800.000 | 15 | 果物 | 国内 |
5 | ぶどう | 300.000 | 45 | 果物 | 国内 |
6 | キウイ | 198.375 | 50 | 果物 | 海外 |
7 | マンゴー | 793.500 | 0 | 果物 | 海外 |
3. 条件に応じた文字列の更新
商品の状態を動的に更新する例です。
def get_stock_status(stock, price):
if stock == 0:
return '品切れ'
elif stock <= 10:
if price >= 500:
return '高級品:残りわずか'
else:
return '残りわずか'
elif stock <= 30:
return '在庫あと少し'
else:
return '在庫十分'
# 在庫状況ラベルの更新
df.loc[:, '在庫状況'] = df.apply(lambda row: get_stock_status(row['在庫'], row['価格']), axis=1)
df
商品名 | 価格 | 在庫 | カテゴリ | 産地 | 在庫状況 | |
---|---|---|---|---|---|---|
0 | りんご | 100 | 50 | 果物 | 国内 | 在庫十分 |
1 | みかん | 80 | 100 | 果物 | 国内 | 在庫十分 |
2 | バナナ | 120 | 30 | 果物 | 海外 | 在庫あと少し |
3 | いちご | 450 | 20 | 果物 | 国内 | 在庫あと少し |
4 | メロン | 800 | 15 | 果物 | 国内 | 在庫あと少し |
5 | ぶどう | 300 | 45 | 果物 | 国内 | 在庫十分 |
6 | キウイ | 150 | 60 | 果物 | 海外 | 在庫十分 |
7 | マンゴー | 600 | 10 | 果物 | 海外 | 高級品:残りわずか |
エラー回避と注意点
データ型の一致
条件付き更新でよく起こるエラーの一つが、データ型の不一致です。
以下は正しい対処法を示しています。
# 価格が文字列として格納されている場合の対処
df.loc[:, '価格'] = pd.to_numeric(df['価格'], errors='coerce')
# 欠損値(NaN)がある場合の対処
df.loc[df['価格'].notnull() & (df['価格'] > 300), 'カテゴリ'] = '高級フルーツ'
条件式の構築
複雑な条件式は、可読性を考慮して段階的に構築することをお勧めします。
# 条件式を分割して構築
price_condition = df['価格'] >= 300
stock_condition = df['在庫'] <= 20
origin_condition = df['産地'] == '海外'
# 条件を組み合わせて更新
target_condition = price_condition & stock_condition & origin_condition
df.loc[target_condition, 'ステータス'] = '要注文'
df
商品名 | 価格 | 在庫 | カテゴリ | 産地 | ステータス | |
---|---|---|---|---|---|---|
0 | りんご | 100 | 50 | 果物 | 国内 | NaN |
1 | みかん | 80 | 100 | 果物 | 国内 | NaN |
2 | バナナ | 120 | 30 | 果物 | 海外 | NaN |
3 | いちご | 450 | 20 | 果物 | 国内 | NaN |
4 | メロン | 800 | 15 | 果物 | 国内 | NaN |
5 | ぶどう | 300 | 45 | 果物 | 国内 | NaN |
6 | キウイ | 150 | 60 | 果物 | 海外 | NaN |
7 | マンゴー | 600 | 10 | 果物 | 海外 | 要注文 |
応用:実務で使えるユーティリティ関数
実務でよく使う更新処理をまとめた関数の例を示します。
def update_prices_with_rules(df, rules):
"""価格更新ルールに基づいて商品価格を一括更新する関数
Parameters
----------
df : pandas.DataFrame
更新対象のデータフレーム
rules : list of dict
更新ルールのリスト。各ルールは以下のキーを持つ辞書:
- condition: 更新条件を指定する関数
- action: 更新内容を指定する関数
Returns
-------
pandas.DataFrame
更新後のデータフレーム
"""
df_copy = df.copy()
for rule in rules:
condition = rule['condition'](df_copy)
df_copy.loc[condition, '価格'] = rule['action'](df_copy[condition])
return df_copy
# 使用例
rules = [
{
'condition': lambda df: (df['在庫'] < 20) & (df['産地'] == '海外'),
'action': lambda df: df['価格'] * 1.2
},
{
'condition': lambda df: df['在庫'] > 100,
'action': lambda df: df['価格'] * 0.9
}
]
updated_df = update_prices_with_rules(df, rules)
まとめ
pandasの条件付き更新は、最初は少し取っつきにくく感じるかもしれません。しかし、基本的な使い方を理解し、実践的なテクニックを身につけることで、Excelよりもずっと柔軟で効率的なデータ処理が可能になります。
特に、複数の条件を組み合わせた更新や、既存の値に基づく動的な更新など、Excelでは複雑になりがちな処理も、pandasでは簡潔に記述できます。
ぜひJupyter Notebookで実際に試してみてください。コードを実行して結果を確認しながら、少しずつ理解を深めていくことをお勧めします😊
Discussion