【问题标题】:Why does foreach return a list of lists为什么foreach返回列表列表
【发布时间】:2016-01-20 17:36:55
【问题描述】:

我让自己陷入了困境,试图理解下面的代码发生了什么。我正在尝试为 data.frame 中的每一行创建一个向量,然后附加到原始向量。我希望下面的代码返回一个数组列表。它似乎返回一个列表列表,内部列表包含数组?我怎样才能得到想要的东西 - 每个元素都附加一个新列作为数组?

df <- mtcars 

library(foreach)
library(iterators)

df$x = foreach (row = iter(df, by='row'))  %do%  {
  profile <- as.numeric(row[,c('mpg', 'cyl', 'disp')])
  return(profile)
}

我期待结果:

df[1,]$x == as.numeric(df[1,c('mpg', 'cyl', 'disp')])

我得到了

df[1,]$x[1] == as.numeric(df[1,c('mpg', 'cyl', 'disp')])

(我使用 == 来表示两个集合是相同的,我意识到 R 可能不会以这种方式实现列表相等运算符)

【问题讨论】:

  • 我不确定你想要得到的输出。您希望从df[1,]$x[1] 得到什么?
  • 我试图让 df[1,]$x 返回 df[1,]$x[1] 所做的 - 即 as.numeric(row[1,c('mpg' , 'cyl', 'disp')])
  • 如果您执行str(df),您将看到df$x 是一个向量列表,这就是您的示例中foreach 返回的内容。如果将 combine 函数更改为 rbind,则 df$x 将是一个矩阵。

标签: r dataframe


【解决方案1】:

foreach 包默认返回输入列表列表(每次迭代一个列表)。这就是为什么您最终得到“错误”输出的原因。您可以通过在 foreach 循环中使用 .combine 选项来更改此设置。如果我理解正确,您希望逐行追加。这可以通过指定.combine = 'rbind' 来实现,它使用熟悉的rbind 函数来组合每个循环迭代的输出。如果顺序无关紧要,还应指定.inorder = FALSE 以加快代码速度。 (TRUE 是默认值,所以如果订单相关,您无需费心。) 所以尝试改用foreach (row = iter(df, by='row'), .combine='rbind') %do% ...,看看它是否能完成这项工作。

【讨论】:

  • 谢谢,这个 cbind 不起作用,但 rbind 似乎可以。如果我使用 rbind 那么我认为结果是一个数组 - 即以下工作 df[1,]$x * df[1,]$x (即产生一个元素明智的乘法)。我很困惑,因为我不是 100% 确定在 Rstudio 中如何检查结果是什么类型,即 typeof(df[1,]$x) 说“double”
  • 哦,感谢您指出这一点,我想我一定是指“rbind”,因为“cbind”对您的问题没有任何意义 - 我编辑了答案。很高兴我能帮忙! :)
【解决方案2】:

这个问题不是foreach引起的。因为您要将向量分配给数据框的单元格(或元素)而不是数据框的列。 foreach 函数必须将此向量强制转换为 list

例如。

df1 <- data.frame(x1=1:4, x2=letters[1:4], stringsAsFactors = FALSE)
df1$x1[1] <- 5:8
# Warning message:
# In df1$x1[1] <- 5:8 :
#   number of items to replace is not a multiple of replacement length
df1
#   x1 x2
# 1  5  a
# 2  2  b
# 3  3  c
# 4  4  d
df1$x1[1] <- list(5:8)
df1
#           x1 x2
# 1 5, 6, 7, 8  a
# 2          2  b
# 3          3  c
# 4          4  d
df1$x1[1]
# [[1]]
# [1] 5 6 7 8
df1$x1[[1]]
# [1] 5 6 7 8

实际上,您应该使用[[ 而不是[

df[1, ]$x[[1]] == as.numeric(df[1,c('mpg', 'cyl', 'disp')])
# [1] TRUE TRUE TRUE

因为list[1] 仍然是一个列表,而list[[1]] 提取了list 的第一个元素。请参阅下面的示例。

lst1 <- list(x1=1:4, x2=letters[1:5])
lst1[1]
# $x1
# [1] 1 2 3 4
lst1[[1]]
# [1] 1 2 3 4

另外,你可以使用:

df$x[[1]]
[1]  21   6 160

代替:

df[1, ]$x[[1]]
# [1]  21   6 160

【讨论】:

  • 这不是问题。
  • 谢谢,但正如@Pascal 所说,我了解如何访问结果,问题是为什么 foreach 返回列表列表以及如何使其仅返回列表
  • foreach 返回一个列表而不是列表的列表。
  • foreach 不会将任何内容强制到列表中:正如您在评论中所说,它只是返回向量列表。但由于 mtcars 没有名为“x”的列,因此分配添加了一个新列,即列表。这与在您的示例中执行 df1$x3 &lt;- list(1:2, 3:4, 5:6, 7:8) 相同。
  • 感谢@SteveWeston,这让我感到困惑,这是将结果从 foreach 分配到 data.frame 的行为让我感到困惑。
猜你喜欢
  • 2015-04-20
  • 1970-01-01
  • 1970-01-01
  • 2022-01-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多