大卫·哈里斯(David Harris)提供了一个很好的答案,但是由于该问题一直在编辑,因此可能会有助于查看其解决方案的详细信息。以下分析的重点是:
为此,我们使用指定的公式创建一些实际的数据,以便我们评估解决方案的准确性。这可以通过以下方式完成R
:
set.seed(17)
n.names <- 1000
groupSize <- 3.5
n.cases <- 5 * n.names # Should exceed n.names
cv <- 0.10 # Must be 0 or greater
groupSize <- 3.5 # Must be greater than 0
proficiency <- round(rgamma(n.names, 20, scale=5)); hist(proficiency)
在这些初始步骤中,我们:
为随机数生成器设置种子,以便任何人都可以准确地再现结果。
指定有多少个工人n.names
。
用规定每组的期望工人数groupSize
。
用指定可用的案例数(观察值)n.cases
。(其中的一些将被淘汰,因为它们是随机发生的,与我们的综合劳动力中的任何工人都不对应。)
安排工作量与根据每个小组的工作“熟练程度”之和预测的工作量随机不同。的值cv
是典型的比例变化;例如,在0.10 此处给出的值对应于典型的10%变化(在某些情况下可能超过30%)。
创建一支具有不同工作能力的人员队伍。此处给出的用于计算的参数proficiency
在最佳工人和最差工人之间产生了超过4:1的范围(以我的经验,对于技术和专业工作而言,甚至可能有点狭窄,但对于常规制造业工作,则可能很宽)。
有了这些综合性劳动力,让我们模拟他们的工作。这相当于schedule
为每个观察值创建一组每个工人()(消除所有根本不涉及工人的观察值),将每个组中工人的熟练程度相加,然后将该总和乘以一个随机值(精确地平均1个)以反映不可避免的变化。(如果根本没有变化,我们可以将这个问题提交给数学站点,在该站点中,受访者可以指出这个问题只是一组联立线性方程组,可以精确地解决这些问题。)
schedule <- matrix(rbinom(n.cases * n.names, 1, groupSize/n.names), nrow=n.cases)
schedule <- schedule[apply(schedule, 1, sum) > 0, ]
work <- round(schedule %*% proficiency * exp(rnorm(dim(schedule)[1], -cv^2/2, cv)))
hist(work)
我发现将所有工作组数据放到一个数据框中进行分析很方便,但可以将工作值分开:
data <- data.frame(schedule)
这是我们从真实数据开始的地方:我们将用data
(或schedule
)编码工人分组,并在work
数组中观察到的工作输出。
不幸的是,如果一些工人总是成对的,R
的lm
程序只是因错误而失败。 我们应该首先检查这种配对。一种方法是在时间表中找到完全相关的工人:
correlations <- cor(data)
outer(names(data), names(data), paste)[which(upper.tri(correlations) &
correlations >= 0.999999)]
输出将列出成对的总是成对的工人:这可以用于将这些工人组合为组,因为至少我们可以估计每个组的生产率,即使不是组内的个人也是如此。我们希望它会吐出来character(0)
。让我们假设它确实如此。
在前面的解释中隐含的一个微妙之处是,所做功的变化是乘法的,而不是累加的。这是现实的:在绝对规模上,一大批工人的产出差异将大于小批工人的产出差异。因此,通过使用加权最小二乘而不是普通的最小二乘,我们将获得更好的估计。在此特定模型中使用的最佳权重是工作量的倒数。(在某些工作量为零的情况下,我通过添加少量以避免被零除的方法来弄虚作假。)
fit <- lm(work ~ . + 0, data=data, weights=1/(max(work)/10^3+work))
fit.sum <- summary(fit)
这只需要一两秒钟。
在继续之前,我们应该执行一些合适的诊断测试。尽管讨论这些问题会使我们在这里走得太远,但R
产生有用诊断的一个命令是
plot(fit)
(这将花费几秒钟:这是一个很大的数据集!)
尽管这几行代码完成了所有工作,并且为每个工作人员吐出了估计的熟练程度,但我们不想浏览所有1000行的输出-至少不是马上。 让我们使用图形显示结果。
fit.coef <- coef(fit.sum)
results <- cbind(fit.coef[, c("Estimate", "Std. Error")],
Actual=proficiency,
Difference=fit.coef[, "Estimate"] - proficiency,
Residual=(fit.coef[, "Estimate"] - proficiency)/fit.coef[, "Std. Error"])
hist(results[, "Residual"])
plot(results[, c("Actual", "Estimate")])
直方图(下图的左下方)是估计值与实际值之间的差异熟练度熟练度,表示为估计标准误差的倍数。对于一个好的程序,这些值几乎总是介于− 2 和 2 并在周围对称分布 0。不过,在有1000名工人参与的情况下,我们完全希望看到其中一些标准化差异会扩展3 乃至 4 远离 0。这就是这里的情况:直方图就像人们希望的那样漂亮。(当然,这可能是一件好事:毕竟这些都是模拟数据。但是对称性确认权重在正确地完成其工作。使用错误的权重会倾向于创建不对称的直方图。)
散点图(该图的右下方)直接将估计的熟练程度与实际熟练程度进行比较。当然,实际上这将是不可用的,因为我们不知道实际的熟练程度:这在于计算机仿真的力量。观察:
如果工作中没有随机变化(设置cv=0
并重新运行代码以查看此情况),则散点图将是一条完美的对角线。所有估计都将是完全准确的。因此,此处看到的分散反映了这种变化。
有时,估计值与实际值相差很远。例如,在(110,160)附近有一个点,其估计熟练程度比实际熟练程度高约50%。在任何大批量数据中,这几乎是不可避免的。如果将估计数用于个人,例如用于评估工人,请记住这一点。总体而言,这些估计值可能是极好的,但是在某种程度上,工作生产率的差异是由于任何个人无法控制的原因造成的,那么对于一些工人来说,这些估计值是错误的:有些过高,有些过低。而且,没有办法确切地说出谁受到了影响。
这是此过程中生成的四个图。
最后,请注意,此回归方法很容易适用于控制可能与小组生产率相关的其他变量。这些可能包括小组人数,每次工作的持续时间,时间变量,每个小组经理的因素等等。只需将它们作为其他变量包括在回归中即可。