我最近发生了一个脱毛事件,经过多次痛苦,我发现在变量上使用scale()
函数阻止了我使用predict
函数。我非常惊讶的是,像变量居中这样简单的东西会从根本上改变它的类型。我不擅长解释这个,所以通过运行下面的代码可能更容易看出我的意思。
df = data.frame(
a=runif(100,45,90),
b=runif(100,0,60),
y=runif(100,-30,60)
)
df$a.center=scale(df$a,scale=FALSE)
df$b.center=scale(df$b,scale=FALSE)
m<-lm(y ~ a.center + b.center, data=df)
predict_df = data.frame(
a.center=c(-10,10),
b.center=c(-5,5)
)
predict_df$predicted = predict(m,predict_df)
我收到错误:
Error: variables ‘a.center’, ‘b.center’ were specified with different types from the fit
与此代码相比,它不使用居中变量并按预期工作:
m2<-lm(y ~ a + b, data=df)
predict_df2 = data.frame(
a=c(-10,10),
b=c(-5,5)
)
predict_df2$predicted = predict(m2,predict_df2)
我还注意到,在执行str(df)
时,居中的变量在它们下面有一个叫“attr”的东西:
'data.frame': 100 obs. of 5 variables:
$ a : num 71.4 57.1 83.9 49 65 ...
$ b : num 54.56 16.76 52.43 34.11 2.43 ...
$ y : num -14.1 -20.8 31.3 -23 51.1 ...
$ a.center: num [1:100, 1] 2.51 -11.77 14.96 -19.89 -3.87 ...
..- attr(*, "scaled:center")= num 68.9
$ b.center: num [1:100, 1] 23.31 -14.49 21.18 2.86 -28.82 ...
..- attr(*, "scaled:center")= num 31.3
所以我的问题是:这里到底发生了什么?我应该避免使用scale
功能吗?有没有一个简单的解决方法,我在str(df)
看到的“attr”是什么?
答案 0 :(得分:4)
查看数据框每列的类,您将看到问题:
> sapply(df, class)
a b y a.center b.center
"numeric" "numeric" "numeric" "matrix" "matrix"
似乎scale
返回一个矩阵,显然数据框很乐意将单列矩阵接受到其中一列,但lm
不考虑单列矩阵相当于一个向量。所以这是3个边缘情况之间的一种奇怪和不幸的相互作用。要解决此问题,请避免使用scale
:
df$a.center <- df$a - mean(df$a)
df$b.center <- df$b - mean(df$b)
或者显式地将结果转换回矢量:
df$a.center <- as.vector(scale(df$a,scale=FALSE))
df$b.center <- as.vector(scale(df$b,scale=FALSE))
或者,您可以使用二维矩阵索引表示法将结果矩阵从scale
分配回数据框的列中,这样做是正确的:
df[,c("a.center", "b.center")] <- scale(df[,c("a", "b")], scale=FALSE)
之后你应该看到这个:
> sapply(df, class)
a b y a.center b.center
"numeric" "numeric" "numeric" "numeric" "numeric"
您对predict
的来电将会成功。
答案 1 :(得分:2)
我会继续使用scale,它会为你提供以下结构化数据框(包括两个由居中生成的矩阵,晕图提到这个)
'data.frame': 100 obs. of 5 variables:
$ a : num 86.1 76.1 75.3 55.3 53.1 ...
$ b : num 48.99 5.99 11.34 56.47 12.9 ...
$ y : num -20.65 8.21 -21.6 13.36 -27.32 ...
$ a.center: num [1:100, 1] 17.85 7.87 7.11 -12.93 -15.16 ...
..- attr(*, "scaled:center")= num 68.2
$ b.center: num [1:100, 1] 19.6 -23.4 -18 27.1 -16.5 ...
..- attr(*, "scaled:center")= num 29.4
使用as.vector
转换是可行的方法。只需在缩放后将它们转换回来。
只有新进程
df$a.center<-as.vector(df$a.center)
df$b.center<-as.vector(df$a.center)
然后您的结果数据再次出现在您希望的结构中:
str(df)
'data.frame': 100 obs. of 5 variables:
$ a : num 86.1 76.1 75.3 55.3 53.1 ...
$ b : num 48.99 5.99 11.34 56.47 12.9 ...
$ y : num -20.65 8.21 -21.6 13.36 -27.32 ...
$ a.center: num 17.85 7.87 7.11 -12.93 -15.16 ...
$ b.center: num 17.85 7.87 7.11 -12.93 -15.16 ...
然后照常运行您的线性模型和预测,取自上面的代码,结果如下:
predict_df
a.center b.center predicted
1 -10 -5 9.534243
2 10 5 16.399051
如果您愿意在插图中列出的每种方法(TRUE,FALSE和数字矢量)之间进行选择,并且知道如何正确选择特定模型所需的内容,我肯定会继续使用缩放。
我建议的原因正是因为 attr。
attr
是矩阵的一个属性,它通过在矢量或帧上运行缩放返回。它是一种保存转换信息而不将其包含在实际数据框中的方法。它有点像关于转换数据的元数据。
在这种情况下,属性是删除NA值后列的平均值,它是用于居中数据的值。您可以通过如下平均计算来验证这一点:
mean(df$a)
[1] 68.23281
mean(df$b)
[1] 29.38355
如果您还选择了缩放比例,则每个都会有第二个值,即删除NA值后列的标准偏差。
R已经为您记录了居中和缩放值。
根据您使用预测的方式以及您的工作所经历的审查,获得这些值非常有用。此外,平均值和标准偏差是一个很好的快速检查,以确定您是否在建模之前正确准备数据。
绝对值得转换为矢量或数据框的麻烦!
如果您自己尝试,请确保设置种子,以便重复转换而不会丢失值。
考虑在使用as.vector
之前重命名数据框,这样您就可以保留原始文件中的属性以备将来使用,并在转换后的集合上运行线性模型。