如何克服此错误:tapply错误(seq_len()

时间:2015-09-08 15:41:24

标签: r dataframe

我使用下面的代码根据每个物种得到每行的线性回归预测,并且它运行得很好:

R2 <- do.call("rbind", as.list( by(iris, iris["Species"], transform, regress=predict(lm(Sepal.Length~Sepal.Width + Petal.Length + Petal.Width,data=iris),newdata=iris,type='response')))
head(R2)
           Sepal.Length Sepal.Width Petal.Length Petal.Width   Species  regress
setosa.1               5.1         3.5          1.4         0.2    setosa 5.021873
setosa.2               4.9         3.0          1.4         0.2    setosa 4.676855
setosa.3               4.7         3.2          1.3         0.2    setosa 4.745967
setosa.4               4.6         3.1          1.5         0.2    setosa 4.814754
setosa.5               5.0         3.6          1.4         0.2    setosa 5.090877
setosa.6               5.4         3.9          1.7         0.4    setosa 5.404108

但是,当我尝试在另一个数据集上实现它时,我希望根据国家/地区名称进行预测(我无法上传),我收到以下错误:

Error in tapply(seq_len(156695L), list(Country = c(72L, 168L, 207L, 94L,  : 
  arguments must have same length.

我该如何解决这个问题?是否有更好的代码可以完成这项工作?

更新: 我添加了两个数据框以更好地解释我的需求: 我希望每个国家/地区lm()预测为df1的新列,基于每个国家/地区应根据数据框df建立的模型。

    df <- read.table(text = "target birds    wolfs     Country
                                3        9         7 a
                                3        8         4 b
                                1        2         8 c
                                1        2         3 a
                                1        8         3 a
                                6        1         2 a
                                6        7         1 b
                                6        1         5 c   ",header = TRUE)
df1<-read.table(text = "target birds    wolfs     Country
                         6        4         5 a
                         4        5         3 a
                         3        8         2 a
                         1        6         4 b
                         3        5         1 a
                         2        2         1 b
                         9        9         4 b
                         8        9         5 c
                         2        3         1 c",header = TRUE)

所以结果应该是如下国家&#34; a&#34;预测应该基于该国家的lm()模型等等。(最后一栏的假数字 - 它仅适用于数据框架结构)

df1<-read.table(text = "target birds    wolfs     Country regress
                         6        4         5     a           5.2
                         4        5         3     a           5.4
                         3        8         2     a           4.8 
                         1        6         4     b           6.6 
                         3        5         1     a           5.0 
                         2        2         1     b           6.1
                         9        9         4     b           6.7
                         8        9         5     c           2.3
                         2        3         1     c           3.1 ",header = TRUE)

1 个答案:

答案 0 :(得分:3)

由于您无法提供实际重现错误的数据和代码示例,因此我只能猜测出错了什么。但我认为我可能找到了实际的原因,所以值得一试。

不幸的是,对我来说,你想要实现的目标也不完全清楚。这主要是因为你的代码没有做你想做的事情(如果我理解你的话)。我认为您要为每个Species创建一个独立模型,即您要创建一个线性拟合,包含属于给定物种的行。这不是您的代码正在做的事情。如果您的目标是别的,请告诉我。不过,部分答案可能仍然有用。

首先让我告诉你你的代码实际上做了什么。这将引导我找出错误消息的原因,最后,我将解释如何实现上述目标。

通过使用函数by,您可以确保transform分别应用于属于给定物种的iris行。但是,在构建模型时,您要告诉它使用iris中的所有数据。因此,对于每个物种,您将获得完全相同的模型,并且在所有三种情况下它将适合所有数据。并且第二次出现同样的问题:当您使用预测时,您告诉函数预测iris中的所有数据。所以,如果你真的想为每个物种建立一个独立的模型,这不是你应该做的。

现在出现错误消息的原因。正如我所提到的,当您预测值时,您可以为iris中的所有行创建预测,而不仅仅是具有给定物种的行。现在iris包含三个物种的数据,每个物种有50行。您的代码为每个物种生成150(而不是50)预测,因为它预测了所有150行。现在R尝试将这150个值作为新列添加到只有50行的数据框中。 R在这种情况下所做的事情被称为回收:它只是重复50行三次,因此你得到一个150行的数据帧。 (阅读https://cran.r-project.org/doc/manuals/R-intro.pdf中的第2.2节,如果这对您来说是新的话。)您可以通过评估nrow(R2)轻松检查这是否真的发生了。 R2有450行,而不是你预期的150行。

因此,为什么在iris示例中没有错误消息,而您的示例中出现错误。这是我只能猜测的地方。但我认为原因是:如果向量可以重复整数次,则回收只能起作用。在虹膜的情况下,这是可能的,因为你想要将50行放大到150,这可以通过重复行3次来完成。但是,如果您的实际代码中有49行必须放大到149,则会出现错误,因为R无法执行此操作。使用iris示例很容易重新创建错误消息。只需通过

重新定义iris即可
iris <- iris[-1, ]

再次运行您的示例代码。您应该收到熟悉的错误消息。

现在到了最后一点:你怎么能真正实现你的目标。解决方案是使用by和更复杂的用户定义函数:

predictions <- by(iris, iris[["Species"]], function(sdat) {
            model <- lm(Sepal.Length ~ Sepal.Width + Petal.Length + Petal.Width, data = sdat)
            prediction <- predict(model, newdata = sdat)
            return (prediction)
})

对于函数的每次调用,sdat将是一个数据框,其中只包含 属于其中一个物种的行。将此数据框用于data中的lm参数将创建仅包含此数据的模型,并且在预测中使用它将仅预测这些数据点。要将这些结果添加到iris,您可以使用

R2 <- transform(iris, regress = unlist(predictions))

要检查结果的质量,您可以绘制真实值与模型结果的关系:

plot(R2$Sepal.Length, R2$regress)