【问题标题】:How to iterate (functionally) through rows of a data.frame in R and process as if looping?如何(功能上)遍历 R 中的 data.frame 行并像循环一样处理?
【发布时间】:2019-10-22 10:50:42
【问题描述】:

是否有一个“应用”类型的方法允许我们遍历 data.frame 并以与循环完全相同的方式处理行?当我执行apply(df, 1, function(row){...}) 时,传递给函数函数的row 不是实际的data.frame 行。

df = data.frame(A=rnorm(3), B=letters[1:3])

for (i in 1:3)
{
  row = df[i,]
  print(row)
  print(class(row))
  print(typeof(row))
  print(row$A)
  print(row$B)
}

apply(df, 1, function(row)
{
  print(row)
  print(class(row))
  print(typeof(row))
  print(row$A)
  print(row$B)
})
> df = data.frame(A=rnorm(3), B=letters[1:3])
> 
> for (i in 1:3)
+ {
+     row = df[i,]
+     print(row)
+     print(class(row))
+     print(typeof(row))
+     print(row$A)
+     print(row$B)
+ }
          A B
1 0.4179416 a
[1] "data.frame"
[1] "list"
[1] 0.4179416
[1] a
Levels: a b c
        A B
2 1.35868 b
[1] "data.frame"
[1] "list"
[1] 1.35868
[1] b
Levels: a b c
           A B
3 -0.1027877 c
[1] "data.frame"
[1] "list"
[1] -0.1027877
[1] c
Levels: a b c
> 
> apply(df, 1, function(row)
+ {
+     print(row)
+     print(class(row))
+     print(typeof(row))
+     print(row$A)
+     print(row$B)
+ })
           A            B 
" 0.4179416"          "a" 
[1] "character"
[1] "character"
 Show Traceback

 Rerun with Debug
 Error in row$A : $ operator is invalid for atomic vectors 

编辑 1

comment to this answer 表示 applydata.frame 转换为矩阵,因此您最终会得到向量。我想这就是问题所在。也许是时候使用专用的data.frame 迭代器了?

编辑 2

正如@thelatemail 指出的那样,这可能真的是For each row in an R dataframe 的副本。

【问题讨论】:

  • 我认为没有办法使用apply 来避免它——你可以使用lapply 而不是seq_len(nrow(df)),但如果你严格地想避免使用for
  • 要清楚,这在?apply 中有记录 - “如果 X 不是数组,而是具有非空暗值的类的对象(例如数据框),如果它是二维的(例如,数据框)或通过 as.array,应用尝试通过 as.matrix 将其强制转换为数组。"
  • 我听到了。但我仍然想知道是否有办法在没有循环的情况下做到这一点。
  • ...这是我的第一条评论 - lapply 对行索引 lapply(seq_len(nrow(df)), function(x) df[x,] ) 或根据您链接的问题使用 by - stackoverflow.com/a/1699296/496803
  • 请尽量避免添加关于人们如何在此处投票的评论,无论是与否决票、潜在重复或问题是否与主题相关。读者将按他们的意愿投票。关于潜在的重复,这些是真诚和乐于助人的精神提供的——如果它们到达就处理它们。没有任何问题作者可以保证 Stack Overflow 没有可能的重复问题。

标签: r dataframe functional-programming apply


【解决方案1】:

除了lapply 在行索引之外,您还可以将lapplysplit 一起使用。请注意,我正在分配结果以防止输出列表打印。

df = data.frame(A=rnorm(3), B=letters[1:3])

row_fun <- function(row) {
  print(row)
  print(class(row))
  print(typeof(row))
  print(row$A)
  print(row$B)
}

test <- lapply(split(df, 1:nrow(df)), row_fun)
#>            A B
#> 1 -0.1566198 a
#> [1] "data.frame"
#> [1] "list"
#> [1] -0.1566198
#> [1] a
#> Levels: a b c
#>            A B
#> 2 -0.2241851 b
#> [1] "data.frame"
#> [1] "list"
#> [1] -0.2241851
#> [1] b
#> Levels: a b c
#>           A B
#> 3 -1.028928 c
#> [1] "data.frame"
#> [1] "list"
#> [1] -1.028928
#> [1] c
#> Levels: a b c

dplyr 的最新版本还提供了group_map,它可以适应使用代词.x 将行作为单行数据框暴露给函数(而不是作为向量,您已经可以使用purrr::pmap。我们只需要创建一个用于分组的rowid变量。请注意,这也会将普通的data.frames强制转换为tbl_df

library(tidyverse)
test2 <- df %>%
  rowid_to_column() %>%
  group_by(rowid) %>%
  group_map(~ row_fun(.x))
#> # A tibble: 1 x 2
#>        A B    
#>    <dbl> <fct>
#> 1 -0.157 a    
#> [1] "tbl_df"     "tbl"        "data.frame"
#> [1] "list"
#> [1] -0.1566198
#> [1] a
#> Levels: a b c
#> # A tibble: 1 x 2
#>        A B    
#>    <dbl> <fct>
#> 1 -0.224 b    
#> [1] "tbl_df"     "tbl"        "data.frame"
#> [1] "list"
#> [1] -0.2241851
#> [1] b
#> Levels: a b c
#> # A tibble: 1 x 2
#>       A B    
#>   <dbl> <fct>
#> 1 -1.03 c    
#> [1] "tbl_df"     "tbl"        "data.frame"
#> [1] "list"
#> [1] -1.028928
#> [1] c
#> Levels: a b c

reprex package (v0.3.0) 于 2019 年 6 月 6 日创建

【讨论】:

  • lapply + split 本质上也是by,这使得这非常接近于之前提出相同解决方案的问题的重复。
  • @Calum -- 希望我能给你一个额外的 +1 来教我有关 reprex 的知识!
  • @thelatemail -- 我明白你的意思。我们会看看是否有人标记它;)哎呀,也许我会自己标记它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-17
  • 2019-10-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多