1 はじめに
オムニチャネルの特徴は, 消費者サイドから見れば, 消費者がネットで販売されるときの価格 (「ネット価格」) と実店舗で販売されるときの価格 (「実店舗価格」) を比較することができるこ とと, 消費者がネットで注文した財を実店舗で受け取ることができること (「店舗受取 (Buy-Online-and-Pick-up-in-Store, BOPS)」) である. 一方, 販売業者サイドから見れば, 店舗受取 により配送費を節約することができる以外に, ネットで注文された財を実店舗から配送すること ができる (「店舗配送 (Ship-From-Store, SFS)」). 店舗配送を行う場合, 実店舗の在庫を利用 することが可能な場合もある1. 〈研究ノート〉オムニチャネル, フルフィルメントおよび
ダイナミック・プライシングに関する一考察
A Note on Omnichannel, Fulfillment and Dynamic Pricing楠田
康之
*Yasuyuki KUSUDA
* 日本福祉大学経済学部 E-mail: [email protected] URL: https://handy.n-fukushi.ac.jp/pub/kusuda/index.html
1 店舗受取に関する理論的研究は, Gao and Su (2016) や Kusuda (2019) を参照. 要 旨
本稿では, Lei et al. (2018) と Harsha et al. (2019) の提示した 2 つのモデルを概観し, オム ニチャネルの中で販売業者がどのように価格とフルフィルメントを決定するべきかという問題につ いて, 論点整理を行う. さらに, オムニチャネルの文脈でも注目されつつあるダイナミック・プラ イシングについても議論し, 価格とフルフィルメントの動学モデルを簡単な数値例を使って計算し, その問題点について記すものである.
そこで問題は, 在庫 (リソース) を異なる販売チャネルにどのように配分するかということと, ネットで発生した需要をどの販売チャネルで取り扱うか (「フルフィルメント」) ということ, お よび, ネットと実店舗においてどのように価格を設定しなければならないかということである. つまり, この枠組みの分析では, 価格, フルフィルメント, 在庫の 3 つの観点から販売業者の行 動を考えなければならない. さらに, この問題を販売が多期間にわたるようなモデル (「動学モ デル」) として考えるならば, 分析はさらに複雑になる. 本稿では, このようなオムニチャネル分析の新しい枠組みについて, フルフィルメントとダイ ナミック・プライシングの観点から考察していく.
2 フルフィルメントとダイナミック・プライシングについて
「フルフィルメント (fulfillment)」 とは, 「商品の受注から決済に至るまでの業務全般のこと」 で, 「梱包・発送業務や入金管理, 在庫管理, 物流管理, 顧客管理などを含む」 (「デジタル大辞 泉」 より引用)2. オムニチャネルが構築された流通システムは複数のフルフィルメント・センター (あるいは, 配送センター) を含むことがあり, さらに, 実店舗もフルフィルメントを行う拠点 として用いることが期待されている. ここで, どのフルフィルメント・センター (以下, FC) または実店舗をどの地域の需要のために用いるかが販売業者の問題となる. 販売業者は全体のフ ルフィルメント費用が最小化するようにフルフィルメントのパターンを決定しなければならない. また, オムニチャネルに関しては, BOPS や SFS を活用することで (あるいは活用しないこと で) フルフィルメントのパターンを変更することが可能である. その意味で, 新しいオムニチャ ネルの分析の中で, フルフィルメントの決定問題は重要な意味を持つ. 一方, ダイナミック・プライシング (「収益管理 (Revenue Management, RM)」 とも呼ばれ る) とは, 需給状況によって価格を変動させる方法のことで, ここ近年, 現実のビジネスの世界 で急速に注目を集めてきた. その理由として, インターネットの発展と, それを用いる E コマー ス (EC) の普及により, 顧客のビッグ・データが収集され, 分析のためのプログラミング技術 や機械学習などの新しい分析手法が普及したことが考えられる. 実際, 米国では, 配車サイトの Uber や , EC サ イ ト の Amazon や eBay , 物 流 業 者 の FedEx や UPS , 宿 泊 施 設 サ イ ト の Airbnb などがダイナミック・プライシングを用いて価格設定を行っている. 日本でも, 最近, プロサッカークラブの横浜 F・マリノスが観覧席の一部にダイナミック・プライシングを導入し たことが話題になった. また, JR 東日本が鉄道運賃に対してダイナミック・プライシングの導 入を検討していることが報道されている. 2 筆者の認識では, 「フルフィルメント」 に相当する別の的確な日本語はいまだにないようである. 本 稿では, 「フルフィルメントを行う」 という表現で, ある財を上記の業務について取り扱うことを表 す.ダイナミック・プライシングは, 航空運賃やホテルの宿泊料金などに対しては古くから採用さ れてきた3. Talluri (2012) によると, ダイナミック・プライシングが適用される財の特徴は以 下の通りである. ・キャパシティが固定されていて, 短期には変更できない ・高い固定費用と低い限界費用 ・実際にリソースを使う前に販売される (予約制など) ・在庫がすぐに陳腐化する ・1 日単位で需要が大きく変化する ・財に対する選好に関して異質的な消費者 ・不特定多数の消費者, したがって消費者をクラス分けしにくい さらに, Talluri (2012) は簡単な数値例を用いて, なぜダイナミック・プライシングが収益 を高めるのか, その基本的なメカニズムについて説明している. 以下, この数値例についてまと めよう. 簡単な数値例 (Talluri (2012) による) ある日に出発する航空機のチケットを 80 座席分, 販売する航空会社を考える. このチケット を購入する可能性のある消費者は 2 つのタイプに分けられる. それは, 1 座席のチケットに対し て 100 ドルまで支払ってもよいと思う 「観光客 (leisure customer)」 と 300 ドルまで支払って もよいと思う 「出張客 (business customer)」 であり, 観光客は 60 人, 出張客は 30 人いる. 観光客は搭乗日の 2 週間以上前に購入することができ, 出張客は搭乗日直前にならないと購入で きないことを航空会社は知っている. そこでまず, 航空会社が何も条件をつけずに単一の価格で チケットを販売する場合を考えよう. もし 100 ドルで販売すると, 観光客も出張客もチケットを 買うので 80 座席がすべて販売され, 航空会社の収益は 8,000 ドルになる. 一方, 300 ドルで販 売すると, 出張客にしか販売できないので, 300 ドル×30 座席=9,000 ドルの収益となる. 次に, 航空会社が条件付きで 2 タイプのチケットを異なる価格で販売する場合を考えよう. つまり, 搭 乗日の 2 週間前までに購入することを条件にチケットを 100 ドルで割引販売し, それ以降の購入 では正規料金 300 ドルで販売するとする. ただし, 割引チケットは 50 座席限定である. すると, 観光客のうち 50 人が 100 ドルの割引チケットを購入し, 出張客の 30 人が 300 ドルの正規チケッ トを購入するので, 収益は 100 ドル×50 座席+300 ドル×30 座席=14,000 ドルとなる. この例でわかるように, 従来のダイナミック・プライシングの本質は, 消費者を属性によって
3 ダ イ ナ ミ ッ ク ・ プ ラ イ シ ン グ モ デ ル の サ ー ベ イ 論 文 と し て , Bitran and Caldentey (2003) , Elmaghraby and Keskinocak (2003) , Talluri and Van Ryzin (2006) , Chen and Simchi-Levi (2012), Talluri (2012) などがある.
セグメントに分け, それぞれに異なる価格で販売する価格差別政策である. これをオムニチャネ ル分析にどのように適用させればよいだろうか? 以下では, Lei et al. (2018) と Harsha et al. (2019) の研究を概観しながら, オムニチャネルとダイナミック・プライシングを結びつけるヒ ントとしたい.
3 価格・フルフィルメント同時決定モデル (JPF)
3. 1 JPF モデルとは価格・フルフィルメント同時決定モデル (Joint Pricing and Fulfillment model, JPF モデル) とは, 複数の販売地域, 複数の販売チャネルを持つ販売業者の動的な最適化問題である. ネット ワークとロジスティクスの活用により, 複数の販売地域に財を販売するような広域販売業者は, 価格とフルフィルメントを同時に決定することで高い収益を得ることができる. この節では, Lei et al. (2018) にしたがい, 価格・フルフィルメント同時決定モデルを概観し, 価格とフルフィ ルメントをそれぞれ調整するよりも, それらを同時に決定するほうが高い収益を実現できること を簡単な例によって示す. Lei et al. (2018) は, 筆者が知る限り, JPF モデルを提示した最初の研究である. 価格とフ ルフィルメントの決定問題を確率的動学モデルとして定式化しているが, そのような問題を解く のは困難なので, ランダマイゼーションによって目的関数の近似値を最適化する 「近似線形問題 (Approximate Linear Program, ALP)」 を考え, その問題を解くために, 2 つのヒューリスティ クス (発見的手法) を考えている. Lei et al. (2018) の価格とフルフィルメントに関する学術的な問題意識は次のとおりである. 昨今の E コマース市場は巨大なものとなってきており, 販売業者が巨額の費用をかけて FC を 建設することが重要になってきた. 一方, 販売業者は頻繁に価格を変更することができて, しか も効率的なフルフィルメントを行うことにより, それに関する費用を削減することができる. こ こで, 価格はネット上で公開されて即時に収益に影響するのに対し, フルフィルメントは物理的 な在庫量を変更するので即時に費用に影響する. つまり, 価格とフルフィルメントは需要と供給 に影響するという意味で, 相互に結びついている. 販売業者の直面する最適化問題の観点から見 れば, 価格とフルフィルメントには, ・フルフィルメント→価格:フルフィルメントによって決定する期待利潤を価格によって最 適化する ・価格→フルフィルメント:価格によって決定する現在の在庫と将来の需要を考えてフルフィ ルメントを最適化する という双方向の関係がある. このような理由により, 販売業者はフルフィルメントを同時に, か つ体系的に決定しなければならない.
3. 2 JPF モデルの数値例 上のような問題意識の上で, 価格・フルフィルメント同時決定モデルが収益を増加させること を, Lei et al. (2018) は 1 財・2 販売地域・2FC による簡単な数値例を用い, 2 つの最適化問題 を比較することで示している. まず 1 つ目は, 総需要量が FC にある在庫量の合計を超えないと いう制約のもとで, 財の価格を 1 つ決定し, 次にその価格のもとで, フルフィルメント費用を最 小化するようにフルフィルメントを決定する問題である. ここでは, これを 「分離型最適化問題」 と呼ぼう. もう 1 つの最適化問題は, 在庫制約を満たしながら, 価格とフルフィルメントを同時 に決定する問題である. これを, 「同時型最適化問題」 と呼ぼう. まず, Lei et al. (2018) の設定を示す. ある 1 つの財を 2 つの販売地域に販売する販売業者が 存在する. この販売業者は 2 つの FC を保有している. 販売地域はミシガン (MI) とオレゴン (OR) の 2 地域, FC の所在地はカリフォルニア (CA) とイリノイ (IL) の 2 地域である. こ の財の需要関数は, オレゴン, ミシガンともに, (p)=116−2p とし, FC の保有する在庫量は, カリフォルニアが CCA=56, イリノイが CIL=60とする4. どの販売地域に対し, どの FC でフル フィルメントを行うかによって, フルフィルメント費用は異なる. カリフォルニアの FC がミシ ガンの需要に対してフルフィルメントを行うためには財 1 単位当たり 41.75 ドルかかり, オレゴ ンの需要に対しては 20.10 ドルかかる. また, イリノイの FC がミシガンの需要に対してフルフィ ルメントを行うためには財 1 単位当たり 18.00 ドル, オレゴンの需要に対しては 38.25 ドルかか る. 各販売地域と FC に対する需要, 在庫量およびフルフィルメント費用を図 1 に示す. このような設定の下で, 分離型最適化問題と同時型最適化問題を解いて比較してみよう. まず, 4 ここで, 需要関数を表す記号に(一般に 「レート関数」 または 「強度 (intensity)」 を表す記号) が用いられているのは, Lei et al. (2018) で議論される動的計画法の中で, 需要がポアソン過程にし たがって発生すると仮定されているからである. 図 1 JPF モデルの数値例 (Lei et al. (2018) より引用)
分離型最適化問題では, 第 1 段階として収入を最大にするような価格 (p) を求め, 第 2 段階で その最適価格を所与として, フルフィルメント費用を最小にするようなフルフィルメントを求め る. このような最適化問題は, 次のように定式化される. 問題 1 (分離型最適化問題) 第 1 段階 maximize p∈{14.22, 30.34} p(116−2p)+p(116−2p) subject to (116−2p)+(116−2p)
Σ
i∈{CA, IL} Ci (1) ここで, 目的関数は 2 販売地域の収入の合計 p(116−2p)+p(116−2p) であり, 制約条件は 2 販 売地域の需要量の合計が 2 つの FC の在庫量の合計を超えないことである. なお, Lei et. al. (2018) の設定では, 価格は 14.22 ドルから 30.34 の間で決定されるとされている. この最適化 問題を解いた結果, 最適解は p'
=29 となる. 2 販売地域の需要量の合計は 116 となるため, 2 つ の FC の在庫量の合計を等号の意味で満たしている. 次に, FCi で行われる販売地域 j のための フルフィルメントを xij, そのときの費用を cijとすると, 第 2 段階の問題は次のようになる. 第 2 段階 minimizexij0 i∈{CA, IL}
Σ
j∈{MI, OR}Σ
cijxij subject toΣ
i∈{CA, IL} xij=58,∀j;Σ
j∈{MI, OR} xij Ci, ∀i (2) つまり, p'
=29 のもとで, フルフィルメント費用を最小化する. ここで, 最初の制約条件は, 販売地域 j のためのフルフィルメントの合計が第 1 段階で得られた需要量 58 と等しくなること, 2 つ目の制約条件は, FCi で行われるフルフィルメントの合計がその FC の在庫量を超えないこ とである. この問題を解くと, 解は x'
CA, MI=0, x'
CA, OR=56, x'
IL, MI=58, x'
IL, OR=2 となり, 最大利潤は p'
(116−2p'
)+p'
(116−2p'
)−Σi∈{CA, IL}Σj∈{MI, OR}cijx'
ij=1117.90 となる.これに対して, 価格とフルフィルメントを同時に決定する同時型最適化問題は次のようになる.
問題 2 (同時型最適化問題) maximize
p∈{14.22, 30.34}, xij0
p(116−2p)+p(116−2p)
Σ
i∈{CA, IL}j∈{MI, OR}
Σ
cijxij (3) subject toΣ
i∈{CA, IL} xij=116−2p,∀j;Σ
j∈{MI, OR} xij Ci, ∀i ここで, 分離型最適化問題との違いは, この問題では利潤を最大化するように価格 (p) とフルフィルメント (xij) を同時に決定していることである. 制約条件は, ある販売地域のための 2 つ の FC のフルフィルメントの合計がその販売地域の需要を満たすこと, および, FCi でのフルフィ ルメントの合計がその FC の在庫量を超えないことである. この最適化問題の解は, p*=30.34, x*CA, MI=0, x*CA, OR=55.32, x*IL, MI=55.32, x*IL, OR=0 となり, 最大利潤は 1249.13 ドルとなる. したがって, 同時型最適化問題で求めた最大利潤は分離型最適化問題に比べて 131.23 ドル大き くなる5. この同時型最適化問題の分離型最適化問題に対する優位性は明快であろう. 分離型最適化問題 の場合, 価格を先に決定しているので, フルフィルメント費用最小化問題において制約が強くなっ ているのに対し, 同時型最適化問題の場合, よりゆるやかな制約のもとで価格とフルフィルメン トをより広範囲に選ぶことができる. さらに, この数値例の直感的な意味を考えるために, 2 つ の最適化問題の解を比較してみよう. 同時型最適化問題の最適価格は分離型最適化問題よりも高 くなっている (p*>p
'
) ので, これにより同時型最適化問題の販売量は分離型最適化問題より も少なくなっている. ところが, フルフィルメント費用を考慮に入れた場合, 分離型最適化問題 の販売量は過剰であり, 在庫を使い切らない同時型最適化問題により費用を削減しつつ利潤をよ り高めることができるのである. (付録 A に, 2 つの最適化問題を解くための Python プログラ ムコードを掲載した. 計算にはモデリング言語ライブラリとソルバーが必要である. 付録 C に, Google Colaboratory を使う場合に必要なインストールの方法を記した.)Lei et al. (2018) は JPF モデルを動学モデルとして提示しているが, 一方, Harsha et al. (2019) は, このモデルを配送センターと実店舗のネットワークを含むオムニチャネルの問題と してとらえた試みである. 次の節では, Harsha et al. (2019) のモデルを考察する.
4 オムニチャネルとフルフィルメント
4. 1 HSU モデルの概要 この節では, Harsha et al. (2019) にもとづいて, 価格・フルフィルメント同時決定モデル にオムニチャネルを導入しよう. Harsha et al. (2019) は, ネットで消費者が注文した財に対し てどのようにフルフィルメントを行うか, 動学モデルを用いて分析している. この節では, まず, Harsha et al. (2019) のモデル (以下, HSU モデル) の概要を示し, その簡略化した数値モデ ルを用いて簡単なシミュレーションを行う.まず, HSU モデルの概要を以下に示す6. ある 1 つの財を複数の販売地域 (zone) において販
5 ただし, Lei et al. (2018) の結果では, p=30.00, xCA, OR=xIL, MI=56, xCA, MI=xIR, OR=0 と報告されて
いる. しかし, そのときの利潤は 1226.40 ドルであるため, p=30.34 が正しい解と考えられる. なお, 価格の制約がない場合を計算してみると, p=38.52, xCA, OR=xIL, MI=38.95, xCA, MI=xIR, OR=0 , 利潤
1517.10 ドルとなり, さらに利潤を上げられることがわかった. 6 以下の説明の中では, Harsha et al. (2019) の表記を一部変えている.
売する販売業者が存在し, 1 つの FC と複数の実店舗を通じて財を販売しているとする. 実店舗 は地域ごとに 1 つずつ存在するとし, ここでは地域 i の実店舗を実店舗 i と呼ぼう (i=1, ..., Z). 地域 i に居住する消費者はネットで財を注文するか, またはその地域の実店舗を訪問して財を購 入する. ネットを通じて発生した需要を 「ネット需要」, 実店舗で発生した需要を 「実店舗需要」 と呼ぼう. ネットで注文された場合, 販売業者は, (1) FC によるフルフィルメント, (2) 実店 舗 i によるフルフィルメント, (3) 実店舗 j (j≠i) によるフルフィルメント, のいずれかを行う. 地域 i においてネット注文を受けて販売する量を sei, 実店舗を訪問してきた消費者に販売する 量を sbiで表し, ネット注文を受けて販売するうち, (1), (2), (3) のフルフィルメントを, そ れぞれ, yei, yii, yjiで表す (i, j=1, ..., Z; j≠i)7. ここで, sei≡yei+yii+yjiである. さらに, (1), (2), (3) のフルフィルメントを行うときの 1 単位当たりの費用を, それぞれ, cei, cii, cjiで表 す. また, (1), (2), (3) のフルフィルメントは, それぞれ, FC の在庫, 実店舗 i の在庫, 実 店舗 j の在庫を用いて行われる. この設定により, 問題は在庫管理を含み, フルフィルメントは 在庫量に依存して決定されることになる. このような設定で, 販売業者が T 期間に財を販売する動学モデルを考えよう. まず, ネット で販売する場合, 価格は同一としなければならないが, 実店舗で販売する場合は, それぞれ異な る価格を設定することができる. そこで, 販売業者が t 期に設定するネット価格を pteとし, 実 店舗の価格を ptbiとしよう (以下ではすべて, t=1, . . . , T). 販売業者は t 期において, 価格 (pte, ptbi), 販売量 (stei, stbi), を同時に決定することができる. ここで, 販売量は需要量をすべて 満たす必要はない. 次に, t 期における FC と実店舗 i の在庫量を, それぞれ, xte, xtbiとする. FC の在庫は各地域のためのフルフィルメントに使われる. 一方, 実店舗の在庫量は, その実店 舗で販売する分と, ネット需要のうち, その実店舗でフルフィルメントが行われる分に使われる. したがって, FC と実店舗 i の在庫量の推移は, それぞれ, xt+1e =xte−(yte 1+…+yteZ), xt+1bi =xtbi− stbi−(yti1+…+ytiZ) となる.
Harsha et al. (2019) は, フルフィルメントは各実店舗のシステム (Order Management System, OMS) により決定される状況を考え, 各期のフルフィルメントは販売業者にとって外 生的かつランダムな変数であると仮定している. ただし, 「在庫割当 (inventory partition)」 という考え方を導入し, 本来の最適化問題をフルフィルメントを政策変数とした近似的な問題に よって解く方法を提示している. そこで, 以下では, 価格, 販売量およびフルフィルメントを政 策変数とし, 販売業者が各期にそれらを決定して期待利潤を最大化するような動学モデルを提示 する. 地域 i で発生したネット需要の需要関数を Dtei(pte, pbit), 実店舗需要の需要関数を Dtbi(pte, ptbi) としよう. これらの需要は販売業者が価格を設定した 「後に」 観察されるランダム変数であ る. したがって, 販売業者は, t 期において, (1) 需要が確定する前に, 期待利潤を最大化する 7 ここで, yjiは, 「地域 i のネット需要に対して地域 j の実店舗においてフルフィルメントを行う量」 という意味であることに注意.
ように価格を決定し, (2) 需要が確定した後に, 在庫量を観察し, 販売量とフルフィルメントを 決定する, という 2 段階意思決定問題を解くことになる. このような販売業者の問題は, 次のよ うなベルマン方程式により表される (Harsha et al. (2019) の (3), (4), (5) 式より). Vt(xt)=maximize pt∈ΩZ+1 EDt
[
(st, yt)∈max t(xt, pt, D t)p t⊥st−c⊥yt+Vt+1(
f(xt, st, yt))
]
, t=1, . . . , T VT+1(xT+1)=q(e ⊥ xT+1) (4) ただし, pt=(pte, ... , pte, ptb1, ... , ptbZ) ⊥ , st=(ste1, ... , steZ, stb1, ... , stbZ) ⊥ , c=(ce1, ... , ceZ, c11, ... , cij, ... , cZZ) ⊥ , yt=(yte1, ... , yteZ, yt11, ... , ytij, ... , ytZZ) ⊥ , xt=(xte, xtb1, ... , xtbZ) ⊥ とし, とする. f(xt, st, yt) は上で示した在庫量の推移を表す関数であり, q を 1 単位当たりのサルベー ジ価値とする (e は要素がすべて 1 である縦ベクトル.) 4. 2 単純化した HSU モデルこのように, Harsha et. al. (2019) では, 1 つの FC と, それぞれ 1 つの店舗が存在する地域 が複数あるような動学的不確実モデルが考察されているが, 実際にこの問題を解くのは非常に困 難である. 本稿では, これをできるだけ単純化したい. そこで以下のような仮定をもうける. ・地域は 1 つ, 実店舗も 1 つ (異なる地域でのフルフィルメントは考えない) ・確定需要 (不確実性は考えない) ・価格, 販売量, 在庫量を, ネットに対してはそれぞれ pe, se, xe, 実店舗に対してはそれ ぞれ pb, sb, xbとする ・需要はすべて販売されなければならない (se=De(pe, pb), sb=Db(pe, pb)) ・ネットの販売は, FC と実店舗においてフルフィルメントが行われる. つまり, ネット需 要のうち, yeを FC でフルフィルメントを行う販売量, ybを実店舗でフルフィルメント を行う販売量とすると, se=ye+yb ・ce, cb>0 を, それぞれ FC と実店舗に対する 1 単位当たりのフルフィルメント費用とする この設定を図 2 に示す. stmiDtmi(pte, ptbi), m=e, b, ∀i stei=ytei+
Σ
jytji, ∀i t(xt, pt, D t)= s 0, y0; (5)Σ
iy t eixte, stbi+Σ
iytjixbi, ∀i以下では在庫制約の意味を考察するために, まず, この問題を 1 期のみで考える. 次の問題は c=(ce, cb) を所与として, p=(pe, pb) と y=(ye, yb) に関して最適化するものである. 問題 (1 期のみの HSU モデル) maximize p0, ye0, yb0 peDe(pe, pb)+pbDb(pe, pb)−ceye−cbyb subject to ye+yb=De(pe, pb), yexe, Db(pe, pb)+ybxb (6) さらに単純化のために需要関数を線形, つまり, De(pe, pb)=120−pe+0.5pb, Db(pe, pb)= 120−pb+0.5peとし, 2 つの数値例を考えよう. 数値例 (1) maximize pe0, pb0, ye0, yb0 pe(120−pe+0.5pb)+pb(120−pb+0.5pe)−30ye−10yb subject to ye+yb=120−pe+0.5pb, ye1000, (120−pb+0.5pe)+yb200 (7) この数値例では, FC でフルフィルメントを行う場合の方が実店舗で行う場合よりも 1 単位当た りのフルフィルメント費用が高いと仮定している. これは, FC からの業務が煩雑なのに対して, 実店舗に直接訪問してきた消費者に販売する場合は業務が簡素化されている状況を想定している. また, 在庫量に関しては FC は多いが, 実店舗は少ない. 実際, FC で在庫切れとなる状況は現 実的ではないだろう. この問題を Python で解いた結果, 解は pe=125.0, pb=120.0, ye=0.0, yb =55.0, se=55.0, sb=62.5 となり, このときの利潤は 13825.0 となる (プログラムコードは付録 B を参照). この問題の解は自明であろう. まず, この問題では, フルフィルメント費用に関して, 図 2 簡略化した HSU モデル
FC の方が実店舗より高いので (ce>cb), 費用を節約するために, 明らかに ye=0 となる. つま り, ネット需要はすべて実店舗でフルフィルメントが行われる. また, FC の在庫量が多いので, 2 番目の制約条件は無視できる. さらに, 3 番目の制約条件も拘束的ではないので内点解が存在 する. このモデルでは, 実店舗の販売に関して費用を考えていないので, その分, ネットで販売 することは実店舗に比べて不利となる. したがって, ネット価格は実店舗価格より高くなり, ネッ ト需要を抑制するのが最適となる. 数値例 (2) maximize pe0, pb0, ye0, yb0 pe(120−pe+0.5pb)+pb(120−pb+0.5pe)−30ye−10yb subject to ye+yb=120−pe+0.5pb, ye1000, (120−pb+0.5pe)+yb100 (8) この数値例は, 数値例(1)の 3 番目の制約条件のみ, 200 を 100 に変更したものである. つまり, 実店舗の在庫量が少なく, この制約条件が制約的になることが予想される. 実際, この問題の解 は, pe=135.0, pb=130.0, ye=7.5, yb=42.5, se=50.0, sb=57.5 となる. この場合, 数値例 (1) と は異なり, ye>0 となって一部のネット需要は FC でフルフィルメントが行われる. 一方, 実店 舗の在庫量に関しては sb+yb=57.5+42.5=100 で拘束的となる. この 2 つの数値例は, 在庫制約の意味に関して示唆を与えるものである. これらの数値例では, FC のフルフィルメント費用が実店舗よりも高いと仮定していた. したがって, 数値例 (1) のよ うに実店舗の在庫制約が拘束的でない場合, FC でのフルフィルメントは 0 となる. しかし, 実 店舗の在庫制約が拘束的となる可能性がある場合, このことは自明ではない. 実際, 数値例 (2) では, 実店舗の在庫をすべて使ってしまうため, FC でのフルフィルメントも活用することが有 利になり, 両在庫が使用されることになる. このことより, 動学モデルのポイントは, どの程度 まで在庫が減ったとき, フルフィルメントに関する決定が変化するか (あるいは変化しないか), ということである. このことを明らかにするために, 2 つの動学モデルを考えてみたい. 4. 3 動学モデルのシミュレーション 上の 1 期のみのモデルを多期間繰り返す動学モデルを考える. 販売期間は 12 期とし, FC の 初期在庫量を 10000, 実店舗の初期在庫量を 1000 とする8. 以下では, 販売業者が毎期毎期, 各 期の価格とフルフィルメントを決定する 「近視眼的動学モデル」 と, 販売期間の前に 12 期の価 格とフルフィルメントを決定する 「フル動学モデル」 の 2 つを計算する. 8 ただし, この動学モデルでは時間割引は含まない. このようなモデルが対象とするのは 1 シーズン (12 週程度) の間に販売する財なので, その設定は妥当であろう.
近視眼的動学モデル 販売業者は各期の期首に在庫量を観察し, その期の価格とフルフィルメントを考える. 在庫量 は各期ごとに変化するが, それ以外は上の 1 期のみのモデルと同じ最適化問題となる. 問題は次 のとおり定式化される. maximize pt e0, ptb0, yte0, ytb0 pte(120−pte+0.5ptb)+ptb(120−ptb+0.5pte)−30yte−10ytb, t=1, . . . , T subject to yte+ytb=120−pte+0.5ptb, t=1, . . . , T ytexte, t=1, . . . , T (120−ptb+0.5pte)+ytbxtb, t=1, . . . , T (9) xt+1e =max{xte−yte, 0}, t=1, . . . , T−1 xt+1b =max{xtb−ybt−(120−ptb+0.5pte), 0}, t=1, . . . , T−1 x1e=10000, x1b=1000 この問題の解を図 3 に示す. この結果からわかるように, 販売業者は第 1 期から第 8 期までネッ ト価格を 125 円, 実店舗価格を 120 円に設定する. また, ネット需要のフルフィルメントに対し ては, 第 8 期までは FC の在庫を使わず, 実店舗の在庫のみ使う. 第 9 期にネット価格と実店舗 価格をともに引き上げ (それぞれ, 135 円と 130 円), 実店舗より FC の在庫によってネット需 要のフルフィルメントを行う. 第 10 期以降は実店舗の在庫が枯渇するので, ネットでのみの販 売となり, すべてのフルフィルメントは FC によって行われる. 最適価格 (左上), 最適フルフィルメント (右上), 最適販売量 (左下), 最適在庫量 (右下) 図 3 近視眼的動学モデルの解
フル動学モデル 最後に, 本来の HSU モデルであるフル動学モデルを考えよう. 販売業者は販売期間の前に 12 期間の価格とフルフィルメントを期間内の総利潤を最大化するように決定する. 問題は次のとお り定式化される. maximize pt e0, ptb0, yte0, ytb0
Σ
T t=1 {pte(120−pte+0.5ptb)+ptb(120−ptb+0.5pte)−30yte−10ytb}, subject to yte+ytb=120−pte+0.5ptb, t=1, . . . , T ytexte, t=1, . . . , T (120−ptb+0.5pte)+ytbxtb, t=1, . . . , T (10) xt+1e =max{xte−yte, 0}, t=1, . . . , T−1 xt+1b =max{xtb−ybt−(120−ptb+0.5pte), 0}, t=1, . . . , T−1 x1e=10000, x1b=1000 計算の結果を図 4 に示す. このモデルの場合, 近視眼的モデルと異なり, 販売業者は 12 期間を 通じてネット価格と実店舗価格を固定する (それぞれ, 135 円と 130 円). フルフィルメントに 関しては, 初期には FC の在庫を用いるが, 後期には実店舗の在庫を用いる. 第 12 期に実店舗 の在庫は枯渇する. つまり, このモデルでは, 期間を通じてネットでの販売を抑制し, フルフィ ルメント費用を節約しようとする. 最適価格 (左上), 最適フルフィルメント (右上), 最適販売量 (左下), 最適在庫量 (右下) 図 4 フル動学モデルの解12 期間の利潤の合計を 2 つのモデルで比較すると, 近視眼的モデルでは 148181 円になるのに 対し, フルモデルでは 158900 円となる (図 5). つまり, フルモデルは近視眼的モデルより 10719 円高い利潤を販売業者にもたらす. 近視眼的モデルでは在庫量の推移を考慮しないので, 初期に実店舗の在庫を使い, 期間中に枯渇させてしまうのに対して, フルモデルでは実店舗の在 庫を慎重に使うことでフルフィルメント費用が上がるのを回避し, その結果全体としては利潤を 上げることになる.
5 おわりに
本稿では, オムニチャネルの中で, 販売業者が価格とフルフィルメントをどのように決定する べきかという問題を, Lei et al. (2018) と Harsha et al. (2019) を引用しながら考えた. いず れの論文も主にモデルの解法を議論したものであるため, ここでは彼らのモデルを簡略化したモ デルを提示し, Python プログラムを用いた数値計算によってこれらのモデルの持つ問題を明ら かにした. この分野での 1 つの論点提示になることを期待したい. 最後に, 本稿で述べなかった 2 つの問題点について記す. まず, 1 つは, これらのモデルは供 給サイドから見たものであり, 消費者行動に関する分析が掘り下げられていない. 楠田 (2020) では, 販売業者が消費者に 3 つのオプション (ネット配送, 店舗受取, 店舗購入) を提示すると きの価格とフルフィルメント戦略について考察した. この分析は Harsha et al. (2018) よりア イデアを得た静学的なモデルであるが, これを動学化するのが将来の課題である. もう 1 つの問 題点は, 在庫量の決定問題である. 上の 2 つのモデルは FC や実店舗に在庫量が決定した後の分 析となっている. しかし, さらに長期的に, 初期在庫量をどのように決定するかが新しいオムニ チャネルの分析の中で 1 つの論点となるかもしれない. 近視眼的動学モデル (左), フル動学モデル (右) 図 5 利潤の比較参考文献
Bitran, G., & Caldentey, R. (2003). An overview of pricing models for revenue management. Manufacturing & Service Operations Management, 5 (3): 203-229.
Chen, X., & Simchi-Levi, D. (2012). Pricing and inventory management. inzer, O., & Phillips, R (eds.), The Oxford Handbook of Pricing Management, (pp. 784-824). Oxford University Press. Gao, F. and Su, X. (2016). Omnichannel retail operations with buy-online-and-pick-up-instore.
Management Science, 63 (8): 2478-2492.
Elmaghraby, W., & Keskinocak, P. (2003). Dynamic pricing in the presence of inventory considera-tions: Research overview, current practices, and future directions. Management Science, 49 (10): 1287-1309.
Harsha, P., Subramanian, S., & Uichanco, J. (2019). Dynamic pricing of omnichannel inventories: honorable mention-2017 M&SOM Practice-Based Research Competition. Manufacturing & Service Operations Management, 21 (1), 47-65.
Lei, Y., Jasin, S., & Sinha, A. (2018). Joint dynamic pricing and order fulfillment for e-commerce re-tailers. Manufacturing & Service Operations Management, 20 (2), 269-284.
Kusuda, Y. (2019). Buy-online-and-pick-up-in-store in omnichannel retailing. arXiv preprint arXiv: 1909.00822.
楠田康之 (2020). 「オムニチャネルにおける価格・フルフィルメント戦略」 (未公刊, 2020 年度日本経済 学会秋季大会報告)
Talluri, K. T. (2012). Revenue management. inzer, O., & Phillips, R (eds.), The Oxford Handbook of Pricing Management (pp. 655-678). Oxford University Press.
Talluri, K. T., & Van Ryzin, G. J. (2006). The Theory and Practice of Revenue Management (vol. 68). Springer Science & Business Media.
付録 A JPF モデルのプログラムコード
Python プログラムコードを掲載する. プログラミングには, ライブラリ Pyomo とソルバー IPOPT が必要. (ただし, ""の部分を書きかえれば別のソルバーでも計算可能である.)
ၥ㢟1㸦ศ㞳ᆺ᭱㐺ၥ㢟㸧 ➨ 1 ẁ㝵
from pyomo.environ import *
# FCࡢῧᏐ㞟ྜ N = ['CA', 'IL'] # FCࡢᅾᗜ㔞 C = {'CA': 56, 'IL': 60} # ࢥࣥࢡ࣮ࣜࢺ࣭ࣔࢹࣝࢆᣦᐃ model = ConcreteModel() # ኚᩘp(౯᱁)ࢆᐉゝ model.p = Var(bounds=(14.22, 30.34)) # ┠ⓗ㛵ᩘࢆタᐃ
def obj_rule(model):
return model.p*(116 - 2*model.p) + model.p*(116 - 2*model.p) model.obj = Objective(rule=obj_rule, sense=maximize)
# ไ⣙ᘧࢆタᐃ
def con_rule(model):
return (116 - 2*model.p) + (116 - 2*model.p) <= sum(C[i] for i in N)
model.con = Constraint(rule=con_rule)
# ࢯࣝࣂ࣮ࢆᣦᐃࡋ࡚ၥ㢟ࢆゎࡃ
opt = SolverFactory("ipopt") results = opt.solve(model)
# ⤖ᯝࡢ⾲♧ model.display() ⤖ᯝ㸸 Model unknown Variables: p : Size=1, Index=None
Key : Lower : Value : Upper : Fixed : Stale : Domain None : 14.22 : 29.000036543092097 : 30.34 : False : False : Reals
Objectives:
obj : Size=1, Index=None, Active=True Key : Active : Value
None : True : 3363.9999999946585
Constraints: con : Size=1
Key : Lower : Body : Upper None : None : 115.99985382763163 : 116.0
➨ 2 ẁ㝵
from pyomo.environ import *
# FCࡢῧᏐ㞟ྜ
N = ['CA', 'IL']
# ᆅᇦࡢῧᏐ㞟ྜ
M = ['MI', 'OR']
# 㓄㏦ࢥࢫࢺ
c = {('CA', 'MI'): 41.75, ('CA', 'OR'): 20.10, ('IL', 'MI'): 18.00, ('IL', 'OR'): 38.25}
# FCࡢᅾᗜ㔞
C = {'CA': 56, 'IL': 60}
# ࢥࣥࢡ࣮ࣜࢺ࣭ࣔࢹࣝࢆᣦᐃ
# ኚᩘx(㓄㏦㔞)ࢆᐉゝ
model.x = Var(N, M, within=NonNegativeReals)
# ┠ⓗ㛵ᩘࢆタᐃ
def obj_rule(model):
return sum(sum(c[i, j]*model.x[i, j] for i in N) for j in M) model.obj = Objective(rule=obj_rule)
# ไ⣙ᘧ1ࢆタᐃ
def con_rule1(model, j):
return sum(model.x[i, j] for i in N) == 58 model.con1 = Constraint(M, rule=con_rule1) # ไ⣙ᘧ2ࢆタᐃ
def con_rule2(model, i):
return sum(model.x[i, j] for j in M) <= C[i] model.con2 = Constraint(N, rule=con_rule2)
# ࢯࣝࣂ࣮ࢆᣦᐃࡋ࡚ၥ㢟ࢆゎࡃ
opt = SolverFactory("ipopt") results = opt.solve(model)
# ⤖ᯝࡢ⾲♧ model.display() ⤖ᯝ㸸 Model unknown Variables: x : Size=4, Index=x_index
Key : Lower : Value : Upper : Fixed : Stale : Domain
('CA', 'MI') : 0 : 0.0 : None : False : False : NonNegativeReals ('CA', 'OR') : 0 : 56.00000056980314 : None : False : False : NonNegativeReals ('IL', 'MI') : 0 : 58.000000009940194 : None : False : False : NonNegativeReals ('IL', 'OR') : 0 : 1.9999994301968598 : None : False : False : NonNegativeReals
Objectives:
obj : Size=1, Index=None, Active=True Key : Active : Value
None : True : 2246.0999898369964
Constraints: con1 : Size=2
Key : Lower : Body : Upper MI : 58.0 : 58.000000009940194 : 58.0 OR : 58.0 : 58.0 : 58.0 con2 : Size=2
Key : Lower : Body : Upper CA : None : 56.00000056980314 : 56.0
IL : None : 59.99999944013705 : 60.0
Cost = 41.75*0 + 20.10* 56 + 18.00*58 + 38.25*2 Profit = 29*(116 - 2*29) + 29*(116 - 2*29) - Cost
⤖ᯝ㸸
1117.8999999999996
ၥ㢟2㸦ྠᆺ᭱㐺ၥ㢟㸧
from pyomo.environ import *
# FCࡢῧᏐ㞟ྜ
N = ['CA', 'IL']
# ᆅᇦࡢῧᏐ㞟ྜ
M = ['MI', 'OR']
# 㓄㏦ࢥࢫࢺ
c = {('CA', 'MI'): 41.75, ('CA', 'OR'): 20.10, ('IL', 'MI'): 18.00, ('IL', 'OR'): 38.25} # FCࡢᅾᗜ㔞 C = {'CA': 56, 'IL': 60} # ࢥࣥࢡ࣮ࣜࢺ࣭ࣔࢹࣝࢆᣦᐃ model = ConcreteModel() # ኚᩘp(౯᱁)ࢆᐉゝ model.p = Var(bounds=(14.22, 30.34)) # ኚᩘx(㓄㏦㔞)ࢆᐉゝ
model.x = Var(N, M, within=NonNegativeReals)
# ┠ⓗ㛵ᩘࢆタᐃ
def obj_rule(model):
return model.p*(116 - 2*model.p) + model.p*(116 - 2*model.p) ¥ - sum(sum(c[i, j]*model.x[i, j] for i in N) for j in M) model.obj = Objective(rule=obj_rule, sense=maximize)
# ไ⣙ᘧ1ࢆタᐃ
def con_rule1(model, j):
return sum(model.x[i, j] for i in N) == 116 - 2*model.p model.con1 = Constraint(M, rule=con_rule1)
# ไ⣙ᘧ2ࢆタᐃ
def con_rule2(model, i):
return sum(model.x[i, j] for j in M) <= C[i] model.con2 = Constraint(N, rule=con_rule2)
# ࢯࣝࣂ࣮ࢆᣦᐃࡋ࡚ၥ㢟ࢆゎࡃ
opt = SolverFactory("ipopt") results = opt.solve(model)
# ⤖ᯝࡢ⾲♧
model.display() ⤖ᯝ㸸
Model unknown
Variables:
p : Size=1, Index=None
Key : Lower : Value : Upper : Fixed : Stale : Domain None : 14.22 : 30.34 : 30.34 : False : False : Reals x : Size=4, Index=x_index
Key : Lower : Value : Upper : Fixed : Stale : Domain
('CA', 'MI') : 0 : 0.0 : None : False : False : NonNegativeReals ('CA', 'OR') : 0 : 55.31999940312728 : None : False : False : NonNegativeReals ('IL', 'MI') : 0 : 55.31999940316573 : None : False : False : NonNegativeReals ('IL', 'OR') : 0 : 0.0 : None : False : False : NonNegativeReals
Objectives:
obj : Size=1, Index=None, Active=True Key : Active : Value
None : True : 1249.1256227401582
Constraints: con1 : Size=2
Key : Lower : Body : Upper MI : 0.0 : -5.968342691176076e-07 : 0.0 OR : 0.0 : -5.96872723690467e-07 : 0.0 con2 : Size=2
Key : Lower : Body : Upper CA : None : 55.31999940312728 : 56.0
IL : None : 55.31999940316573 : 60.0
付録 B HSU モデルのプログラムコード 1 ᮇࡢࡳࡢ HSU ࣔࢹࣝ
ᩘ್(1)
from pyomo.environ import *
# 㟂せ㛵ᩘࡢษ∦ alpha = 120 # ௦᭰ຠᯝ beta = 0.5 # ࣇࣝࣇ࣓ࣝࣥࢺ࣭ࢥࢫࢺ ce = 30 cb = 10 # ᅾᗜ㔞 ze = 1000 zb = 200 # ࢥࣥࢡ࣮ࣜࢺ࣭ࣔࢹࣝࢆᣦᐃ model = ConcreteModel() # ኚᩘp(౯᱁)ࢆᐉゝ
model.pb = Var(within=NonNegativeReals) # ኚᩘy(㓄㏦㔞)ࢆᐉゝ
model.ye = Var(within=NonNegativeReals) model.yb = Var(within=NonNegativeReals)
# ┠ⓗ㛵ᩘࢆタᐃ
def obj_rule(model):
return model.pe*(alpha - model.pe + beta*model.pb) ¥ + model.pb*(alpha - model.pb + beta*model.pe) ¥ - ce*model.ye - cb*model.yb
model.obj = Objective(rule=obj_rule, sense=maximize) # ไ⣙ᘧ1ࢆタᐃ
def con_rule1(model):
return model.ye + model.yb == (alpha - model.pe + beta*model.pb) model.con1 = Constraint(rule=con_rule1)
# ไ⣙ᘧ2ࢆタᐃ
def con_rule2(model):
return model.ye <= ze
model.con2 = Constraint(rule=con_rule2) # ไ⣙ᘧ3ࢆタᐃ
def con_rule3(model):
return (alpha - model.pb + beta*model.pe) + model.yb <= zb model.con3 = Constraint(rule=con_rule3)
# ࢯࣝࣂ࣮ࢆᣦᐃࡋ࡚ၥ㢟ࢆゎࡃ
opt = SolverFactory("ipopt") results = opt.solve(model)
# ⤖ᯝࡢ⾲♧
print('pe:', round(model.pe(), 2))
print('pb:', round(model.pb(), 2))
print('ye:', round(model.ye(), 2))
print('yb:', round(model.yb(), 2))
print('se:', round(alpha - model.pe() + beta*model.pb(), 2))
print('sb:', round(alpha - model.pb() + beta*model.pe(), 2))
print('Profit:', round(model.obj(), 2)) 㸦ᩘ್(2)ࡣ┬␎㸧 ㏆ど║ⓗືᏛࣔࢹࣝ import numpy as np # ㈍ᮇ㛫 T = 12 # ౯᱁ࡢิ Pe = np.zeros(T) Pb = np.zeros(T) # ࣇࣝࣇ࣓ࣝࣥࢺࡢิ
Ye = np.zeros(T) Yb = np.zeros(T) # ㈍㔞ࡢิ Se = np.zeros(T) Sb = np.zeros(T) # ₶ࡢิ Profit = np.zeros(T) # ᅾᗜ㔞ࡢิ Xe = np.zeros(T+1) Xb = np.zeros(T+1)
from pyomo.environ import *
# 㟂せ㛵ᩘࡢษ∦ alpha = 120 # ௦᭰ຠᯝ beta = 0.5 # ࣇࣝࣇ࣓ࣝࣥࢺ࣭ࢥࢫࢺ ce = 30 cb = 10 # ᅾᗜ㔞ࡢึᮇ್ Xe[0] = 10000 Xb[0] = 1000 for t in range(T): # ࢥࣥࢡ࣮ࣜࢺ࣭ࣔࢹࣝࢆᣦᐃ model = ConcreteModel() # ኚᩘp(౯᱁)ࢆᐉゝ
model.pe = Var(within=NonNegativeReals) model.pb = Var(within=NonNegativeReals) # ኚᩘy(㓄㏦㔞)ࢆᐉゝ
model.ye = Var(within=NonNegativeReals) model.yb = Var(within=NonNegativeReals)
# ┠ⓗ㛵ᩘࢆタᐃ
def obj_rule(model):
return model.pe*(alpha - model.pe + beta*model.pb) ¥ + model.pb*(alpha - model.pb + beta*model.pe) ¥ - ce*model.ye - cb*model.yb
model.obj = Objective(rule=obj_rule, sense=maximize) # ไ⣙ᘧ1ࢆタᐃ
def con_rule1(model):
return model.ye + model.yb == (alpha - model.pe + beta*model.pb)
model.con1 = Constraint(rule=con_rule1) # ไ⣙ᘧ2ࢆタᐃ
def con_rule2(model):
return model.ye <= Xe[t]
model.con2 = Constraint(rule=con_rule2) # ไ⣙ᘧ3ࢆタᐃ
def con_rule3(model):
return (alpha - model.pb + beta*model.pe) + model.yb <= Xb[t]
model.con3 = Constraint(rule=con_rule3)
# ࢯࣝࣂ࣮ࢆᣦᐃࡋ࡚ၥ㢟ࢆゎࡃ
opt = SolverFactory("ipopt") results = opt.solve(model) # ౯᱁
Pe[t] = model.pe() Pb[t] = model.pb()
# ࣇࣝࣇ࣓ࣝࣥࢺ
Ye[t] = model.ye() Yb[t] = model.yb() # ㈍㔞
Se[t] = alpha - model.pe() + beta*model.pb() Sb[t] = alpha - model.pb() + beta*model.pe() # ₶
Profit[t] = model.obj()
# ᅾᗜ㔞ࡢ᥎⛣
Xe[t+1] = max(Xe[t] - Ye[t], 0)
Xb[t+1] = max(Xb[t] - Yb[t] - Sb[t], 0) ࢢࣛࣇᥥ⏬㸦౯᱁ࡢࡳ㸧 import numpy as np import matplotlib.pyplot as plt %matplotlib inline plt.xlabel('Period') plt.ylabel('Yen')
plt.plot(range(1, 13), Pe, label="Online Price", marker="o", color="C1")
plt.plot(range(1, 13), Pb, label="Store Price", marker="o", color="C0")
plt.legend() plt.grid() plt.show()
ࣇࣝືᏛࣔࢹࣝ
# ᮇ㛫 T = range(1, 13) # 㟂せ㛵ᩘࡢษ∦ alpha = 120 # ௦᭰ຠᯝ beta = 0.5 # ࣇࣝࣇ࣓ࣝࣥࢺ࣭ࢥࢫࢺ ce = 30 cb = 10 # ࢥࣥࢡ࣮ࣜࢺ࣭ࣔࢹࣝࢆᣦᐃ model = ConcreteModel() # ኚᩘp(౯᱁)ࢆᐉゝ
model.pe = Var(T, within=NonNegativeReals) model.pb = Var(T, within=NonNegativeReals) # ኚᩘy(㓄㏦㔞)ࢆᐉゝ
model.ye = Var(T, within=NonNegativeReals) model.yb = Var(T, within=NonNegativeReals) # ኚᩘx(ᅾᗜ㔞)ࢆᐉゝ
model.xe = Var(T, within=NonNegativeReals) model.xb = Var(T, within=NonNegativeReals)
# ┠ⓗ㛵ᩘࢆタᐃ
def obj_rule(model):
return sum(model.pe[t]*(alpha - model.pe[t] + beta*model.pb[t]) ¥ + model.pb[t]*(alpha - model.pb[t] + beta*model.pe[t]) ¥ - ce*model.ye[t] - cb*model.yb[t] for t in T)
model.obj = Objective(rule=obj_rule, sense=maximize) # ไ⣙ᘧ1ࢆタᐃ
def con_rule1(model, t):
return model.ye[t] + model.yb[t] == (alpha - model.pe[t] + beta*m odel.pb[t])
model.con1 = Constraint(T, rule=con_rule1) # ไ⣙ᘧ2ࢆタᐃ
def con_rule2(model, t):
return model.ye[t] <= model.xe[t] model.con2 = Constraint(T, rule=con_rule2) # ไ⣙ᘧ3ࢆタᐃ
def con_rule3(model, t):
return (alpha - model.pb[t] + beta*model.pe[t]) + model.yb[t] <= model.xb[t]
model.con3 = Constraint(T, rule=con_rule3) # ไ⣙ᘧ4ࢆタᐃ
def con_rule4(model, t):
return model.xe[t+1] == model.xe[t] - model.ye[t] model.con4 = Constraint(range(1, 12), rule=con_rule4)
# ไ⣙ᘧ5ࢆタᐃ
def con_rule5(model, t):
return model.xb[t+1] == model.xb[t] - model.yb[t] - (alpha - mode l.pb[t] + beta*model.pe[t])
model.con5 = Constraint(range(1, 12), rule=con_rule5) # ไ⣙ᘧ6ࢆタᐃ
def con_rule6(model):
return model.xe[1] == 10000
model.con6 = Constraint(rule=con_rule6) # ไ⣙ᘧ7ࢆタᐃ
def con_rule7(model):
return model.xb[1] == 1000
model.con7 = Constraint(rule=con_rule7)
# ࢯࣝࣂ࣮ࢆᣦᐃࡋ࡚ၥ㢟ࢆゎࡃ
opt = SolverFactory("ipopt") results = opt.solve(model)
Pe = list(model.pe.get_values().values()) Pb = list(model.pb.get_values().values()) Ye = list(model.ye.get_values().values()) Yb = list(model.yb.get_values().values())
Se = [alpha - model.pe.get_values()[t] + beta*model.pb.get_values() [t] for t in T]
Sb = [alpha - model.pb.get_values()[t] + beta*model.pe.get_values() [t] for t in T]
Xe = list(model.xe.get_values().values()) Xb = list(model.xb.get_values().values())
Profit = [model.pe.get_values()[t]*(alpha - model.pe.get_values()[t] ¥
+ beta*model.pb.get_values()[t]) ¥
+ model.pb.get_values()[t]*(alpha - model.pb.get_values() [t] ¥
+ beta*model.pe.get_values()[t]) ¥
- ce*model.ye.get_values()[t] - cb*model.yb.get_values()[t] for t in T] ࢢࣛࣇᥥ⏬㸦౯᱁ࡢࡳ㸧 import numpy as np import matplotlib.pyplot as plt %matplotlib inline plt.xlabel('Period') plt.ylabel('Yen')
plt.plot(T, Pe, label="Online Price", marker="o", color="C1") plt.plot(T, Pb, label="Store Price", marker="o", color="C0") plt.legend()
plt.grid() plt.show()
付録 C Google Colaboratory と最適化問題
Google Colaboratory は, Google が提供する Jupyter Notebook 形式の Python プログラム 環境であり, Google アカウントを持っていれば無料で使うことができる. (ただし, 時間制限な どの制約がある.) Google Colaboratory には Numpy, Pandas, Matplotlib などの主要ライブ ラリがインストールされているが, 本稿のように, 最適化問題を Python で解く場合, さらにモ デリング言語ライブラリやソルバーをインストールする必要がある. この付録では, ライブラリ Pyomo とソルバー GLPK, IPOPT をインストールして使う方法を記す (2020 年 11 月現在).
上記のライブラリやソルバーは Anaconda (Python のパッケージを提供するプラットフォー ム) によってインストールすることができるが, Google Colaboratory には Anaconda 自体が インストールされていない. そこで, 代わりに Miniconda というものをインストールし, その コマンドによって上記のライブラリとソルバーをインストールし, それらにパスを通す. Google Colaboratory のセルで, 先頭に ! をつけることで仮想マシンのコマンドを制御できる ので, 次のようなコマンドをセルに書いて一度に以上の作業を行う.
インストール後, !conda list で Pyomo, GLPK, IPOPT がリストにあることを確認する. ただし, この方法は, Google Colaboratory の制限のため, ランタイム (ノートブックの実 行環境) がリセットされれば消えてしまう. したがって, Google Colaboratory を起動するた び, 上記の手順を踏む必要がある.
!wget https:
//repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh
!bash Miniconda3-latest-Linux-x86_64.sh -b -f -p /usr/local
!conda install -y -c conda-forge pyomo
!conda install -y -c conda-forge glpk
!conda install -y -c conda-forge ipopt
import sys