1 在庫管理問題

企業や産業システムでは、原料・製品が供給から需要へと流れていく過程で それらを貯蔵する機能が必要である。この貯蔵容量と、それを運用管理する 最適の方法を決定する。

  1. 在庫の要する費用
  2. 問屋への発注のための費用
  3. 品切れが発生した場合にこうむる損失

これらの合計を最小にし、利益を最大にする場合、 いつ、どれだけ、問屋に発注すれば良いのかを考える。

2 在庫モデル

\(Q\)は販売店の在庫とし、一日に売れる個数を\(P\)個とする。 在庫量が基準発注点\(Q1\)をわったとき、\(a\)個の発注をする。 商品の入荷は\(lt\)日後とする。 ここで、売上個数\(P\)は毎日平均\(AL\)個のポアソン分布に従い、 入荷遅れ\(lt\)は平均\(ET\)、標準偏差\(ST\)の正規分布に従うとする。 さて、\(Q1\)の最適な値は何か。

設定を以下の通りで定める。

tend <- 1000  # 期間(日)
#tend1 <- 150 # Q1=10と固定した時にシミュレートした期間(日)
#P <- rpois(1,AL) # 売れた個数(個)
a <- 100     # 一回の入荷量(個)
c1 <- 20     # 一日一個当たりの在庫費用(円/個・日)
c2 <- 10000  # 一回の発注に伴う費用(円/回)
c3 <- 500    # 品切れ一個あたりに伴う損失(円/個)
SP <- 7000   # 売値
PC <- 5000   # 仕入れ単価
AL <- 5      # 一日の平均売上個数(個)
ET <- 6      # 納品するまでの平均日数(日)
ST <- 2      # 納品されるまでの日数の標準偏差
k  <- 30     # jの取りうる値
lt <- -1     # 商品が届くまでの時間(日):平均ET、標準偏差STの正規分布に従う
SC <- 0  # i日までの在庫量の総数(個)
nn <- 0  # 発注回数(回)
LS <- 0  # 売りそこなったものの総数(個)
YK <- 0  # 売上個数の総数

Q  <- rep(NA,tend)  # 現在庫量(個)
#SC <- # i日までの在庫量の総数(個)
#nn <- # 発注回数(回)
#LS <- # 売りそこなったものの総数(個)
#YK <- # 売上個数の総数
Q1 <- rep(NA,k)     # 発注基準個数(個)
RR <- rep(NA,k)     # 総売り上げ

Q[1]  <- a+5  # 初期の在庫数(個)
#lt   <- -1   # 発注していない状態
SC <- Q[1] #一日目の在庫数の総数
nn <- 0    #一日目の発注回数は0
LS <- 0    #一日目に売りそこなったものの数
YK <- 0    #一日目は売った個数ゼロ

3 \(Q1\)を固定した時の在庫数の変化

発注基準個数を\(Q1=10\)個とした時の在庫変化のシミュレーションを与える。

#わかりやすくするため、150日間のシミュレーションを行う。
tend1 <- 150

# Q1をj=2,つまりQ1=10と固定する。
j <- 2
  Q1[j] <- j*5 # 発注基準個数(個)
  Q <- rep(NA, tend1) # 現在庫量(個)
  Q[1] <- a+5 # 初期の在庫数(個)
#グラフ設定
  xlim <- c(0,tend1)
  ylim <- c(-20,Q1[j]+a)  
  
# Q1=10の時のtend期間での在庫変化シミュレーション
  for(i in 2:tend1){
    #●売り出し
    P <-rpois(1,AL) # 売れた個数(個)
    Q[i] <- Q[i-1]-P  # 在庫は(昨日の在庫量)-(今日の売り上げ個数)
    # ここで需要が供給を上回ってしまった場合のプログラムが必要
    
    
    if(Q[i-1] > 0){ # 在庫があるとき
      if(Q[i]<0){ # 昨日の在庫数が正で今日の在庫数が負の時
        LS <- LS - Q[i]  ; # 売りそこなった数が増える 
        SC <- SC       ; # 在庫は無いので総数は昨日のまま
        YK <- YK + Q[i-1]; # 売った数は昨日の在庫分全て
        Q[i] <- 0                # 在庫は0としておく
      }else{ # 昨日の在庫数が正で今日の在庫数が正の時
        LS <- LS     ; # 売りそこなった数無し
        SC <- SC + Q[i]; # 在庫の総数に今日の在庫数が加算される
        YK <- YK + P     # 売上総数に今日の売り上げ分が加算される
      }    
    }else{ # 在庫が無い時
      LS <- LS-Q[i] ; YK <- YK; # 売りそこなった数が増え、売上無し
      if(Q[i]<0){ # 昨日の在庫数が負で、今日の在庫数も負の時
        SC <- SC; # 在庫は無いので総数は昨日のまま
        Q[i] <- 0 # 在庫は0としておく
      }else{ # 昨日の在庫数が正で、今日の在庫数が正の時
        SC <- SC + Q[i]  # 在庫の総数に加算される
      } 
    }
  
    #●在庫の補充
    lt <- lt-1 # 今日から見て在庫が届くまでの日数は昨日より1日引いたもの。
    if(lt == 0){
      Q[i] <- Q[i]+a ; nn <- nn +1
      # もし今日が入荷日であれば在庫は今日の個数+a。発注回数が1増える。
    }else{Q[i] <- Q[i] ; nn <- nn
      # 入荷日でなければ在庫は今日の個数のまま。発注回数そのまま。
    }
    if((Q[i] <= Q1[j]) && (lt < 0)) { # もし在庫が基準値より無く、注文していなければ
      lt <- ceiling(abs(rnorm(1,ET,ST))) # 正規分布に従って〇日遅れで入荷されますよ。
    }else{
      if(lt < 0){
        lt <- lt + 1 # 在庫が十分にあって、注文していなければlt=-1で保ちます。
      }else{
        lt <- lt # 在庫がない状態で注文済みの時はそのまま
                 # 在庫有りで注文済みという場合が仮にあったとしてもそのままとしておく
      }
      
    }
      
# 在庫Qの変化をプロットする    
# plotのフォント指定
par(family="HiraKakuProN-W3")
plot(Q[1:i], xlim=xlim, ylim=ylim, xlab="日にちi(日)", ylab="在庫量Q(個)", type="l");  par(new=T)
# 発注基準個数Q1=10の線
par(family="HiraKakuProN-W3")
curve(0*x+Q1[j], from = 0, to = tend1, xlim=xlim, ylim=ylim, xlab="", ylab="", col="#1e90ff", type="l")

# Q1=10のときの利益RRを求める
    SC1 <- SC * c1 # 在庫費用の累計
    SC2 <- nn * c2 # 発注費用の累計
    SC3 <- LS * c3 # 品切れ損失の累計
    RR[j] <- (SP-PC) * YK -SC1-SC2-SC3
  }
# Q1=10と固定した時の在庫変化シミュレーション終わり↑

\(tend1\)日での在庫量\(Q\)の変化が見られる。青の直線は発注基準個数\(Q1=10\)の線。この線を下回った時に注文をするという仕組みである。

4 発注基準個数\(Q1\)を変えたときの在庫量変化の相違

# Q1をjと固定する。
# Q1=5,10,…,k*5   パターンを考える。
# グラフ設定
xlim <- c(0,tend)
ylim <- c(-20, k*5+a)
for(j in 1:k){
  lt <- -1
# 以下先ほどの命令と同様------------------------------------------------------------------------
  Q1[j] <- j*5 # 発注基準個数(個)
  Q <- rep(NA, tend) # 現在庫量(個)
  Q[1] <- a+5 # 初期の在庫数(個)
# Q1=j*5 の時のtend期間での在庫変化シミュレーション
  for(i in 2:tend){
    #●売り出し
    P <-rpois(1,AL) # 売れた個数(個)
    Q[i] <- Q[i-1]-P  # 在庫は(昨日の在庫量)-(今日の売り上げ個数)
    
    # 元々の在庫の在る・無しで「売り損ない数・在庫数・売った数」の総数が変わる
    if(Q[i-1] > 0){
      if(Q[i]<0){
        LS <- LS-Q[i]  ;  
        SC <- SC       ; 
        YK <- YK+Q[i-1]; 
        Q[i] <- 0
      }else{
        LS <- LS     ; 
        SC <- SC+Q[i]; 
        YK <- YK+P
      }   
    }else{
      LS <- LS-Q[i] ;
      YK <- YK      ; 
      if(Q[i]<0){
        SC <- SC; 
        Q[i] <- 0
      }else{SC<- SC+Q[i]
      } 
    } 
    #●在庫の補充
    lt <- lt-1 # 今日から見て在庫が届くまでの日数は昨日より1日引いたもの。
    if(lt == 0){
      Q[i] <- Q[i]+a ; nn <- nn +1
      # もし今日が入荷日であれば在庫は今日の個数+a。発注回数が1増える。
    }else{Q[i] <- Q[i] ; nn <- nn
      # 入荷日でなければ在庫は今日の個数のまま。発注回数そのまま。
    }
    if((Q[i] <= Q1[j]) && (lt < 0)) { # もし在庫が基準値より無く、注文していなければ
      lt <- ceiling(abs(rnorm(1,ET,ST))) # 正規分布に従って〇日遅れで入荷されますよ。
    }else{
      if(lt < 0){
        lt <- lt + 1 # 在庫が十分にあって、注文していなければlt=-1で保ちます。
      }else{
        lt <- lt # 在庫がない状態で注文済みの時はそのまま
                 # 在庫有りで注文済みという場合が仮にあったとしてもそのままとしておく
      }
      
    }
    
# Q1=j*5のときの利益RRを求める
    SC1 <- SC * c1 # 在庫費用の累計
    SC2 <- nn * c2 # 発注費用の累計
    SC3 <- LS * c3 # 品切れ損失の累計
    RR[j] <- (SP-PC) * YK -SC1-SC2-SC3
  }
# Q1=j*5と固定した時の在庫変化シミュレーション終わり↑-------------------------------------------

# 在庫量変化の相違をグラフに表わす。
  par(family="HiraKakuProN-W3")
  plot(Q, xlim=xlim, ylim=ylim, xlab="日にちi(日)", ylab="在庫量Q(個)", type="l")
  ;  par(new=T)
# 発注基準個数Q1の線
  par(family="HiraKakuProN-W3")
  curve(0*x+Q1[j], from = 0, to = tend, xlim=xlim, ylim=ylim, xlab="", ylab="", col="#1e90ff", type="l")
}

発注基準個数\(Q1\)が上がるにつれて、在庫が足りなくなるということが無くなる。しかし、在庫がありすぎても在庫を管理する費用がかかる。

そこで、発注基準個数\(Q1\)と利益\(RR\)の関係を求めよう。

4.1 発注基準個数\(Q1\)と利益\(RR\)の関係(データ)

先ほどと同様にシミュレートし、得た値を表示する。

“Q1” : 発注基準個数(個) “YK” : 売上個数の累計(個) “LS” : 品切れのため、売り損なった個数の累計(個) “nn” : 発注回数(回) “SC1”: 在庫費用の累計 “SC2”: 発注費用の累計 “SC3”: 品切れ損失の累計 “RR” : 総売り上げ

を表す。

## [1] "Q1"  "YK"  "LS"  "nn"  "SC1" "SC2" "SC3" "RR"
## [1]       5    3755    1194      37  720800  370000  597000 6001245
## [1]      10    4061     871      40  789040  400000  435500 6362020
## [1]      15    4050     889      40  810420  400000  444500 6712103
## [1]      20    4323     727      43  819260  430000  363500 7063754
## [1]      25    4566     448      45  908260  450000  224000 7401690
## [1]      30    4685     330      46  936540  460000  165000 7703509
## [1]      35    4851     295      48  991680  480000  147500 7937367
## [1]      40    4887     130      48 1063380  480000   65000 8092306
## [1]      45    4946      58      49 1181800  490000   29000 8149006
## [1]      50    5034      31      50 1299300  500000   15500 8145755
## [1]      55    5132      26      51 1308580  510000   13000 8123118
## [1]      60    4876      24      49 1466000  490000   12000 7988382
## [1]      65    5024       7      50 1527400  500000    3500 7899967
## [1]      70    4949       1      49 1661760  490000     500 7824481
## [1]      75    4907       0      49 1773600  490000       0 7710507
## [1]      80    5010       0      50 1824900  500000       0 7637355
## [1]      85    5139       0      51 1930540  510000       0 7514446
## [1]      90    5073       0      51 2078680  510000       0 7439540
## [1]      95    4914       0      49 2223720  490000       0 7315893
## [1]     100    4978       0      50 2237320  500000       0 7247692
## [1]     105    4938       0      50 2349800  500000       0 7138541
## [1]     110    4964       0      50 2450420  500000       0 7032785
## [1]     115    5078       0      51 2515080  510000       0 6932476
## [1]     120    5035       0      51 2690460  510000       0 6833238
## [1]     125    4970       0      50 2725260  500000       0 6736912
## [1]     130    4852       0      49 2906200  490000       0 6651883
## [1]     135    5049       0      51 2991900  510000       0 6539819
## [1]     140    5184       0      52 3028280  520000       0 6456680
## [1]     145    4950       0      50 3153060  500000       0 6344632
## [1]     150    4983       0      51 3226220  510000       0 6258201

4.2 発注基準個数\(Q1\)と利益\(RR\)の関係(グラフ)

上のグラフを元に\(Q1\)\(RR\)の関係を表すグラフを作成する。

ここではデータを3次曲線により近似する。 \(Q1\)を無限大に飛ばすと、利益は0に近づくが3次曲線の場合 無限大に行くので、本来この近似のやり方は好ましくない。 区間や領域を絞って回帰モデル化する局所回帰でやるとよい。

グラフが最大値をとる点が最大利益の点であるので、その時の\(Q1\)が適切な発注基準個数となる。

# nls関数にて3次式で近似する。
result <- nls(RR ~ (a * Q1^3 + b * Q1^2 + c * Q1 + d), start = c(a=0, b=0, c=0, d=0))
predict.c <- predict(result)

xlim <- c(0,k*5)
ylim <- c(min(RR,predict.c),max(RR,predict.c))

for(i in 1:k){
# 発注基準個数Q1と利益RRの点をプロットする
  par(family="HiraKakuProN-W3")
plot(Q1, RR, xlim=xlim, ylim=ylim, type="p", xlab="発注基準個数 Q1", ylab="利益 RR") ;  par(new=T)
# 近似曲線を描く
par(family="HiraKakuProN-W3")
plot(Q1[1:i], predict.c[1:i], type="l", xlim=xlim, ylim=ylim, xlab="",ylab="")}

4.3 適切な発注基準個数\(Q1\)

利益が最大の時は以下の通り。

max(predict.c)
## [1] 8065339

グラフから適切な発注基準個数を求めることができる。

## elapsed 
##  19.031