分析预测
所有的预测基本都会产生偏差,因为需求是一个随机变量,良好的预测应该不仅仅是一个数字,而是大概率会落入的一个区间范围
主观预测
- 复合法 - 数据的集合,如:销售人员复合法、选举民意测验复合法
- 客户调查 - 基于客户反馈做出的预测
- 领导层集体预测法 - 由少量专家做出的预测
- 德尔菲法 - 反复汇编并重新考虑个人意见,直到组织内达成共识
客观预测
使用之前的数据客观地进行预测
- 因果模型 - 将需求设为“D”,根本原因设为“n”,因果模型是一个函数,将需求“D”表示为“n”个根本原因
- 时间序列法 - 归纳过去、现在和未来的规律
- 过去数据可能具有以下特征:
- 趋势
- 季节性/周期
- 随机性
- 过去数据可能具有以下特征:
预测平稳序列
平稳序列的特点就是:未来和过去相拟
报童问题(不确定的环境中匹配需求与供应)就是平稳序列的典型案例
平稳时间序列具有以下形式:
- 是常数,有时是样本平均值
- 是随机变量,均值为0
- 标准差为
预测平稳序列的方法有:移动平均法、指数平滑法
平均值、标准差
需求分布平均值:
需求标准差:
算术平均值公式如下:
算术标准差公式如下:
总体标准差(如果总体是一个完整的总体,分母也可以使用n):
t = 1,...,n
样本标准差:
标准差修正
如果样本标准差与总体标准差差距较大,就要考虑样本选择是否正确
如果样本选择正确,直接使用样本标准差即可,也可以根据实际场景对样本标准差进行修正
随着n越来越大,校正项消失
周期预测公式
从周期t预测未来的n个周期,可以使用如下表达式:
如果只预测一个周期,可以简写为
从周期t-1预测周期t
移动平均法
移动平均数是n个最新观测值的算术平均值
MA(n)表示n个数据点的移动平均数
简单点说就是,直接用最近n期的平均值作为下一期的预测值
因为预测值是一个范围值,我们可以使用标准差来预估范围区间
移动平均法的数据是等权的,如果我们想给最新的数据较高的权重,较早的数据较低的权重,可以使用指数平滑法
已知100期的销量,分别使用全部样本、最新20期样本、最新时期样本预算下一期的销量,示例如下:
import numpy as np
num = np.array([
29, 43, 40, 55, 75, 65, 75, 47, 77, 61, 56, 53, 18, 42, 50, 36, 50, 65, 33, 66, 79, 38, 75, 53, 66, 45, 60, 35, 52,
41, 67, 22, 76, 38, 62, 40, 51, 34, 70, 68, 64, 15, 45, 45, 36, 78, 81, 54, 47, 61, 58, 32, 54, 49, 29, 63, 44, 56,
64, 49, 57, 47, 52, 52, 62, 62, 55, 50, 55, 60, 51, 61, 73, 52, 60, 49, 58, 70, 27, 57, 52, 50, 33, 53, 54, 60, 57,
57, 63, 64, 62, 58, 42, 33, 50, 59, 48, 62, 41, 41
])
# 使用全部样本预测下一期
print(round(num.mean(), 2))
print(round(num.std(ddof=1), 2))
# 使用MA(20)预测下一期
print(round(num[-20:].mean(), 2))
print(round(num[-20:].std(ddof=1), 2))
# 使用MA(10)预测下一期
print(round(num[-10:].mean(), 2))
print(round(num[-10:].std(ddof=1), 2))
根据上面的示例,可以发现MA(20)的标准差较小,初步可以判断MA(20)较为准确
移动平均法的缺点:
如果把移动平均法应用于趋势序列,往往会产生滞后
- 如果呈上升趋势,则移动平均预测值通常会低于需求量
- 如果呈下降趋势,则移动平均预测值通常会高于需求量
无法解释为什么未来需求会以某种方式表现出来
预测误差
- e:error,误差
- t:time,周期
- F:forecast,预测
- D:demand,需求
绝对平均离差(MAD):
均方误差(MSE):
平均绝对百分比误差(MAPE)
一个好的预测过程将具有较低的MAD值、MSE值、MAPE值
我们可以通过比对预测误差(后视镜方法)来调整样本范围,从而使得预测更为准确
import numpy as np
num = np.array([
29, 43, 40, 55, 75, 65, 75, 47, 77, 61, 56, 53, 18, 42, 50, 36, 50, 65, 33, 66, 79, 38, 75, 53, 66, 45, 60, 35, 52,
41, 67, 22, 76, 38, 62, 40, 51, 34, 70, 68, 64, 15, 45, 45, 36, 78, 81, 54, 47, 61, 58, 32, 54, 49, 29, 63, 44, 56,
64, 49, 57, 47, 52, 52, 62, 62, 55, 50, 55, 60, 51, 61, 73, 52, 60, 49, 58, 70, 27, 57, 52, 50, 33, 53, 54, 60, 57,
57, 63, 64, 62, 58, 42, 33, 50, 59, 48, 62, 41, 41
])
# 计算最新20期的预测误差、绝对平均离差(MAD)、均方误差(MSE)、百分比误差及其平均值
arr2 = []
for i in (range(-20, 0)):
arr2.append(i)
arr1 = np.array(arr2) - 20
avg = []
for i in range(20):
avg.append(round(num[arr1[i]:arr2[i]].mean(), 2))
# 预测误差 = 预测值 - 实际值
e_t = np.array(avg) - num[-20:] # type:np.ndarray
print(e_t)
# 绝对平均离差(MAD)= 求和(预期误差的绝对值)/个数
mad = np.abs(e_t).sum() / 20
print(round(mad, 2))
# 均方误差(MSE)= 求和(预期误差的平方)/个数
mse = (e_t * e_t).sum() / 20
print(round(mse, 2))
# 平均绝对百分比误差(MAPE)=求和(预测值/实际值)/个数 * 100
mape = (np.abs(e_t / num[-20:])).sum() / 20 * 100
print(round(mape, 2))
A/F比有助于理解预测准确性
- A:actual demand,实际需求
- F:forecast,预测
- A/F < 1,预测小于实际
- A/F = 1,预测较为准确
- A/F > 1,预测大于实际
预测趋势序列
简单的趋势序列,我们可以拟合一条趋势线来进行预测
线性回归法
- Dt - 对周期t的需求做出的预测
- t - 周期
- b - 斜率
- a - 截距
回归分析是一种统计学上分析数据的方法,目的在于了解两个或多个变量间是否相关、相关方向与强度,并建立数学模型以便观察特定变量来预测研究者感兴趣的变量
是指自变量可以解释因变量的比例,用于判断回归线的优劣,即模型的拟合程度。介于0到1之间,越靠近1说明散点越靠近回归线,拟合的越好,通常达到0.8左右就很好了
普通最小二乘法(OLS)
- 通过最小化均方误差来拟合趋势线
- 直线 是通过n个数据点拟合的趋势线
- 选择不同的参数a和b,来最小化数据点离趋势线距离的平方的均值
黄石公园最近50年每年的游客访问数量折线图以及线性回归拟合
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import font_manager
my_font = font_manager.FontProperties(fname='/System/Library/Fonts/Supplemental/Songti.ttc')
x = [1904, 1905, 1906, 1907, 1908, 1909, 1910, 1911, 1912, 1913, 1914, 1915, 1916, 1917, 1918, 1919, 1920, 1921, 1922,
1923, 1924, 1925, 1926, 1927, 1928, 1929, 1930, 1931, 1932, 1933, 1934, 1935, 1936, 1937, 1938, 1939, 1940, 1941,
1942, 1943, 1944, 1945, 1946, 1947, 1948, 1949, 1950, 1951, 1952, 1953, 1954, 1955, 1956, 1957, 1958, 1959, 1960,
1961, 1962, 1963, 1964, 1965, 1966, 1967, 1968, 1969, 1970, 1971, 1972, 1973, 1974, 1975, 1976, 1977, 1978, 1979,
1980, 1981, 1982, 1983, 1984, 1985, 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014]
y = [13727, 26188, 17182, 16414, 19542, 32545, 19575, 23054, 22970, 24929, 20250, 51895, 35849, 35400, 21275, 62261,
79777, 81651, 98223, 138352, 144158, 154282, 187807, 200825, 230984, 260697, 227901, 221248, 157624, 161938,
260775, 317998, 432570, 499242, 466185, 486936, 526437, 579696, 185746, 61696, 86593, 189264, 807917, 937776,
1018279, 1131159, 1110524, 1163894, 1350295, 1326858, 1328900, 1368500, 1457800, 1595900, 1442400, 1408700,
1443300, 1524100, 1925200, 1872500, 1929300, 2062500, 2130300, 2210000, 2229700, 2193700, 2297300, 2120500,
2236888, 2061700, 1928900, 2239500, 2519200, 2481900, 2618380, 1892908, 2000269, 2521831, 2368897, 2347242,
2222027, 2226159, 2363756, 2573194, 2182113, 2644442, 2823572, 2920537, 3144405, 2912193, 3046145, 3125285,
3012171, 2889513, 3120830, 3131381, 2838233, 2758526, 2973677, 3019375, 2868317, 2835651, 2870295, 3151343,
3066580, 3295187, 3640185, 3394326, 3447729, 3188030, 3513484]
plt.figure(figsize=(18, 8), dpi=80)
# 使用Matplotlib画近50年的折线图
plt.plot(x[-50:], y[-50:], color='orange', marker='o')
plt.xticks(range(1960, 2021, 10))
_y = range(0, 4000001, 500000)
_y_ticks = [str(i) for i in _y]
plt.yticks(_y, _y_ticks)
# y轴的作图范围
plt.ylim(0, 4000001)
plt.grid(alpha=0.4)
plt.xlabel("年", fontproperties=my_font)
plt.ylabel("访问数量", fontproperties=my_font)
plt.title("最近50年每年的游客访问数量", fontproperties=my_font)
# 一次多项式拟合,相当于线性拟合,默认使用最小二乘法
fit = np.polyfit(x[-50:], y[-50:], 1)
# 生成拟合函数
fit_fn = np.poly1d(fit) # type: np.poly1d
def formatFnToStr(fit_fn):
fit_fn = str(fit_fn)
fit_fn = fit_fn.replace(" ", '')
fit_fn = fit_fn.split("x-")
return 'y={}x-{}'.format(format(float(fit_fn[0]), '.0f'), format(float(fit_fn[1]), '.0f'))
# 画拟合线
plt.plot(x[-50:], fit_fn(x[-50:]), label=formatFnToStr(fit_fn))
plt.figlegend(loc="center")
plt.show()
普通最小二乘法(多元)
- Y是结果变量
- 是预测变量
- a是截距或常数
- 是系数或斜率
- e是随机误差
OLS估算能最小化 Y(预测)- Y(实际)之和的a和b的值
当预测变量彼此之间的相关性较低时,OLS往往能更好地发挥作用
随着相关性变高,可能会出现共线性问题,从而导致
- 估算的精确度降低,因为如果两个变量非常相似,我们不清楚是其中哪个变量产生了结果
- 估算可能会更多地受到一些观察结果的影响
关于共线性问题没有明确的阈值,但是我们通常会将相关性设定为0.5-0.7,具体取决于数据集和变量的大小
如果存在高度相关的变量,可以考虑删除其中一些变量
只有数值数据可以用于回归分析,如果需要使用文本数据,首先应确定与员工流失密切相关的指标变量,然后再用该变量将文本数据转换为数值数据
相关性:
相关性是指两个变量之间的相关程度,通常用相关系数来衡量。在统计学中,有两种常用的相关系数:Pearson相关系数和Spearman秩相关系数。其中,Pearson相关系数是最常用的一种,它的值介于-1和1之间。当两个变量的线性关系增强时,相关系数趋于1或-1;当一个变量增大,另一个变量也增大时,表明它们之间是正相关的,相关系数大于0;如果一个变量增大,另一个变量却减小,表明它们之间是负相关的,相关系数小于0;如果相关系数等于0,表明它们之间不存在线性相关关系
import pandas as pd
df = pd.read_excel("/home/data/example.xlsx", sheet_name='员工属性概览') # type: pd.DataFrame
df = df[
['流失代码', '年龄', '差旅代码', '日薪', '离家的距离', '教育程度', '环境满意度', '性别代码', '时薪', '工作投入', '职级', '工作满意度', '月收入', '月薪', '曾受雇的公司数',
'加班代码', '加薪百分比', '绩效评级', '关系满意度', '股票期权级别', '总工龄', '去年接受培训的次数', '工作生活平衡', '司龄', '任现职年限', '距离上次晋升的年数',
'与当前经理共事的年数']]
print(df.corr())
EXCEL回归示例:
- R:线性回归系数是预测值和真实值Y之间的相关性
- R方:拟合优度(线性回归系数的平方)是输出变量中方差的百分比,可以通过我们的预测变量进行解释。它的值在0到1之间。如果拟合优度为1,则意味着我们的预测变量可以完美地预测Y
- 调整R方:修正后的拟合优度解释了分析中使用的预测因子数量
- 标准误差:解释了估算中的干扰
- 观察值:样本数量
EXCEL回归示例2:
- 如果员工拥有学士学位(系数为0.05),离职概率会高5%(数据集已清洗为1或0)
- 如果员工经验丰富(系数为-0.005),即工作时间每增加一年,离职的概率下降0.5%
- 学士学位的p值约为0.478,即学士学位的系数值不等于0的可能性是48%,因此我们不太相信能够将学士学位作为人员流失预测因子
- 根据经验法则,p值小于0.05的变量通常被视为具有统计显著性。因此,这些变量包括企业内的任期、工作时间、薪资,以及去年是否申请过内部工作
在Python中,有几个常用的库可以用来实现多元线性回归。以下是一些常见的库以及它们的优劣势:
statsmodels:
- 优势:statsmodels是一个专注于统计模型的库,提供了丰富的统计分析工具,包括回归分析。它的回归分析结果摘要包含了详细的统计信息,如回归系数、P值、置信区间等。适合需要详细统计分析报告的情况。
- 劣势:在大规模数据集上可能性能较低,不太适用于处理大数据。
scikit-learn:
- 优势:scikit-learn是一个通用机器学习库,支持多元线性回归以及其他许多机器学习算法。它易于使用,适合处理中等规模的数据集。由于其广泛的机器学习功能,可以在同一库中进行多种分析。
- 劣势:相对于statsmodels,scikit-learn在回归结果摘要的统计信息方面较为简化。
numpy和scipy:
- 优势:numpy和scipy是科学计算的核心库,可以用于数值分析和优化问题,包括多元线性回归。可以根据自己的需求编写更加定制化的回归分析代码。
- 劣势:需要更多手动操作来计算回归系数等参数,适用于对算法和计算细节有较高控制需求的用户。
TensorFlow和PyTorch:
- 优势:这些库主要用于深度学习,但也可以用于回归问题。它们提供了强大的数值计算和自动求导功能,适用于处理复杂的回归任务,如神经网络模型。
- 劣势:相对于前面提到的专门库,使用深度学习库进行回归分析可能会过于复杂,特别是对于简单的线性回归问题。
如果需要详细的统计分析报告,可以考虑使用statsmodels。如果需要更广泛的机器学习功能,并且对回归结果的详细统计信息不是主要关注点,那么scikit-learn可能更适合
对于定制化需求,可以使用numpy和scipy。如果想要探索更复杂的回归问题,甚至结合深度学习,可以考虑使用TensorFlow或PyTorch
import statsmodels.api as sm
import pandas as pd
df = pd.read_excel("/home/data/example.xlsx", sheet_name='员工属性概览') # type: pd.DataFrame
# print(df.info())
# print(df.describe())
# print(df.head(5))
# print(df.tail(5))
# exit('s')
Y = df['流失代码']
X = df[['年龄', '差旅代码', '日薪', '离家的距离', '教育程度', '环境满意度', '性别代码', '时薪', '工作投入', '职级']]
# 执行最小二乘线性回归
model = sm.OLS(Y, sm.add_constant(X)).fit()
# 输出回归结果摘要
print(model.summary())
文件 提取码: e4id
季节性
季节性是数据的一种模式,指有些变化会定期重复,通过以下方式计算季节性因子
- 计算整个数据集的样本均值
- 计算每个季节的数据集的样本均值(如:春夏秋冬、1月到12月、春节、国庆等等)
- 计算每个季节的样本均值除以整个数据集的样本均值(如:春/整,夏/整...)
- 反季节序列(除去季节性因子),将数据中的每个观察值除以对应的季节因子即可
import numpy as np
import pandas as pd
from matplotlib import font_manager
my_font = font_manager.FontProperties(fname='/System/Library/Fonts/Supplemental/Songti.ttc')
df = pd.DataFrame({
'January': [64.4, 65.28, 69.77, 72.68, 72.3, 72.95, 72.82, 74.89, 76.55, 78.02, 78.89],
'February': [68.1, 68.6, 71.58, 76.07, 75.71, 75.91, 75.28, 77.35, 77.92, 78.9, 80.77],
'March': [72.43, 75.13, 79.58, 81.31, 81.57, 82.19, 81.08, 83.39, 82.7, 84.43, 84.99],
'April': [72.13, 76.17, 76.64, 81.34, 81.38, 80.09, 82.1, 82.55, 82.13, 83.61, 82.81],
'May': [73.98, 74.41, 77.52, 80.39, 81.27, 81.34, 81.32, 82.51, 84.58, 84.45, 84.84],
'June': [78.58, 80.72, 82.27, 84.56, 86.24, 84.24, 85.37, 86.32, 85.98, 86.62, 86.98],
'July': [80.98, 82.2, 83.94, 84.95, 86.24, 84.11, 87.09, 86.9, 87.14, 86.83, 86.46],
'August': [78.74, 78.74, 80.34, 80.9, 84.89, 83.35, 84.97, 85.2, 85.59, 86.61, 85.53],
'September': [66.93, 70.39, 74.12, 73.78, 75.61, 76.07, 79.42, 79.81, 81.82, 80.64, 80.9],
'October': [71.47, 74.23, 75.94, 77.5, 78.45, 79.76, 82.22, 83.32, 83.63, 84.23, 82.77],
'November': [70.45, 73.21, 76.53, 77.98, 77.66, 75.89, 79.17, 81.19, 83.48, 82.78, np.nan],
'December': [72.52, 72.74, 75.81, 76.57, 75.6, 79.17, 79.87, 80.85, 81.11, 81.54, np.nan],
}, index=[2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013]) # type: pd.DataFrame
# 1. 样本总体平均值
all = []
for i in df:
all.append(df[i])
arr = np.array(all)
all_mean = arr[np.isnan(arr) == False].mean()
print(all_mean)
# 如果不在意细微误差的话,可以进行2次平均
all_mean_other = df.mean().mean()
# 2. 每月的平均值
month_mean = df.mean()
print(month_mean)
# 3. 季节性因子
month_factor = month_mean / all_mean
print(month_factor)
# 4. 反季节序列(除去季节性因子)
df_new = df / month_factor
print(df)
print(df_new)
RFM
- R(recency)最近一次消费,权重最高
- F(frequency)消费频率,权重中等
- M(monetary value)消费金额,权重最低
BTYD
Buy Till You Die
用于预测长期"购买"和"死亡"的强有力工具
该模型使用3种输入信息:
- 最近一次消费(R)
- 消费频率(F)
- 每种R/F组合的客户数量
边际收益
当边际收益等于边际成本时,利润最大化
换句话说,当你增加一单位产量时,你所获得的收益与你所付出的成本相等,这时你的利润最大
总结
- 对下1个周期做出预测
- 未来和过去相拟,移动平均法等
- 数据存在趋势,回归分析等
- 对多个周期之后的情况做出预测
- 概率:BTYD模型等