理髮師的難題
我的理髮師 Stacey 總是裝出一副幸福的表情,但經常強調如何管理她的時間。今天斯泰西遲到了我的約會,非常抱歉。理髮時,我想知道:她的標準約會應該多長時間?(如果可以暫時忽略客戶對乾淨整數的偏好)。
需要考慮的是某種“漣漪效應”,一個很晚的客戶可能會導致一連串的預約延遲。實際上,由於害怕這些壓力日,美髮師直覺地學會了將約會的間隔時間越來越長。但是一個最佳的,優雅的解決方案必須由一些統計天才來實現..(如果我們稍微降低現實)
讓我們假設
a) 剪髮時間呈正態分佈,並且
b) 只有一個美髮師。
預約時間過長的成本顯然是浪費了美髮師等待下一次預約的時間。讓我們每分鐘花費 1 美元。
但如果預約時間不夠長,下一位顧客就會一直等待,這對於熱愛顧客的 Stacey 來說是每分鐘 3 美元的成本。
- Stacey 每天工作長達 8 小時,並且有足夠的需求,她可以滿足盡可能多的約會
- 平均理髮需要她 30 分鐘,有性病。開發 10 分鐘。(我們還假設男士剪裁和女士剪裁相同!)
編輯 - 有些人正確地指出,Stacey 可以在他們指定的時間之前照顧早期客戶。這增加了另一層複雜性,但如果我們將其視為一個非常現實的問題,我們需要將其包括在內。讓我們忘記我的 90/10 假設,嘗試一個可能更接近現實的假設。
- 有些顧客遲到,有些顧客早到。顧客的平均遲到 2 分鐘,標準差為 2 分鐘(聽起來很接近現實,不是嗎?)
她的約會到底應該多長時間?
@alexplanation 抱歉,我已將球門柱移到你身上!我相信 R 讀者會欣賞你的回答。
這個問題有很多活動部分,這使得它適合模擬。
首先,正如貓王在評論中提到的那樣,斯泰西似乎應該預約 16 次,因為每次約半小時。但是你知道,隨著約會開始延遲,事情開始變得越來越晚——所以如果 Stacey 只在她還有半個小時的時候才開始約會(掃地的頭髮就這麼多了,嗯,Stacey ?) 如果我們使用水晶球來安排沒有休息時間的約會,那麼我們將有少於 16 個可能的空檔。
在下一個模擬中,我們可以研究成本曲線作為預約時間的函數。當然,其餘參數最終也會在這裡發揮作用——實際上,Stacey 不會安排她的約會相隔幾分鐘,但這讓我們對正在發生的事情有了一些直覺。
我還繪製了 Stacey 必須作為顏色工作的時間。我決定 Stacey 永遠不會在 7:30 之後安排她的最後一次約會,但有時約會會遲到,或者有延遲!你可以看到她回家的時間是量化的,所以隨著約會的時間變長,你會少一個約會,然後就不必工作到很晚了。而且我認為這是這裡缺少的元素-也許安排您的約會相隔 45 分鐘很好,但是如果您可以將其壓縮到 40 分鐘,您將獲得額外的約會。該成本已包含在 Stacey 的等待中(這就是成本上漲的原因隨著約會時間的延長而增加),但您對 Stacey 等待時間的估計可能不正確。
無論如何,有趣的問題!並且是學習一些 ggplot 優點並記住我的 R 語法非常不穩定的好方法。:)
我的代碼如下 - 請隨時提供改進建議。
要生成頂部圖的代碼:
hairtime = 30 hairsd = 10 nSim = 1000 allCuts = rep(0,nSim) allTime = rep(0,nSim) for (i in 1:nSim) { t = 0 ncuts = 0 while (t < 7.5) { ncuts = ncuts+1 nexthairtime = rnorm(1,hairtime,hairsd) t = t+(nexthairtime/60) } allCuts[i] = ncuts allTime[i] = t } hist(allCuts,main="Number of haircuts in an 8 hour day",xlab="Customers")
第二次模擬要長很多…
nSim = 100 allCuts = rep(0,nSim) allTime = rep(0,nSim) allCost = rep(0,nSim) lateMean = 10 lateSD = 3 staceyWasted = 1 customerWasted = 3 allLengths = seq(30,60,0.25) # Keep everything in 'long form' just to make our plotting lives easier later allApptCosts = data.frame(matrix(ncol=3,nrow=length(allLengths)*nSim)) names(allApptCosts) <- c("Appt.Length","Cost","Time") ind = 1 # for every appointment length... for (a in 1:length(allLengths)) { apptlen = allLengths[a] # ...simulate the time, and the cost of cutting hair. for (i in 1:nSim) { appts = seq(from=0,to=(8-hairtime/60),by=apptlen/60) t = 0 cost = 0 ncuts = 0 for (a in 1:length(appts)) { customerArrival = appts[a] # late! if (runif(1)>0.9) { customerArrival = appts[a]+rnorm(1,lateMean,lateSD)/60 } waitTime = t-customerArrival # negative waitTime means the customer arrives late cost = cost+max(waitTime,0)*customerWasted+abs(min(waitTime,0))*staceyWasted # get the haircut nexthairtime = rnorm(1,hairtime,hairsd) t = customerArrival+(nexthairtime/60) } allCost[i] = cost allApptCosts[ind,1] = apptlen allApptCosts[ind,2] = cost allApptCosts[ind,3] = t ind = ind+1 } } qplot(Appt.Length,Cost,geom=c("point"),alpha=I(0.75),color=Time,data=allApptCosts,xlab="Appointment Length (minutes)",ylab="Cost")+ geom_smooth(color="black",size=2)+ opts(axis.title.x=theme_text(size=16))+ opts(axis.title.y=theme_text(size=16))+ opts(axis.text.x=theme_text(size=14))+ opts(axis.text.y=theme_text(size=14))+ opts(legend.text=theme_text(size=12))+ opts(legend.title=theme_text(size=12,hjust=-.2))