更快/更好:循环遍历数据帧的每一行或将其拆分成一个长度为`nrow`,R [英] What is faster/better: Loop over each row of a dataframe or split it into a list of length `nrow` , R

查看:13
本文介绍了更快/更好:循环遍历数据帧的每一行或将其拆分成一个长度为`nrow`,R的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我只是在想,这是否是一个应该考虑的严重权衡。 假设您在R中有一个数据帧,并且想要对每个观测(行)执行一个操作。 我知道迭代行已经是一个微妙的问题,所以我只是想知道三个选项中的哪一个:

  • 每行上正常的for循环
  • 将数据帧拆分成nrow元素列表,对每个元素进行操作并将结果绑定在一起
  • 并行执行上述操作

在没有任何基准测试的情况下,这基本上就是我用伪代码要求的:


library(future.apply)

n = 1000000
x = 1:n
y = x + rnorm(n, mean=50, sd=50)

df = data.frame(
  x = x,
  y = y
)

# 1)
# iterating over each row with normal for loop
for(r in 1:nrow(df)){
  row = df[r, ]
  r = f(row)
  df[r, ] = row
}

# 2)
# create a list of length nrow(df) and apply do something to each list element
# and rowbind it together
res = df %>% split(., .$x) %>% lapply(., function(x){
  r = f(x)
})

bind_rows(res, .id="x")  

# 3)
# create a list of length nrow(df) and apply do something to each list element in parallel
# and rowbind it together

res = df %>% split(., .$x) %>% future_lapply(., function(x){
  r = f(x)
})
bind_rows(res, .id="x")  

上面的选项可能都不是最好的,所以我很乐意对此有任何想法。抱歉,如果这是一个非常天真的问题。我才刚刚开始使用R

推荐答案

我经常用tibble %>% nest %>% mutate(map) %>% unnest这个方案。 请看下面的示例。

library(tidyverse)
n = 10000

f = function(data) sqrt(data$x^2+data$y^2+data$z^2)
tibble(
  x = 1:n,
  y = x + rnorm(n, mean=50, sd=50),
  z = x + y + rnorm(n, mean=50, sd=50)
) %>% nest(data = c(x:z)) %>% 
  mutate(l = map(data, f)) %>% 
  unnest(c(data, l))

输出

# A tibble: 10,000 x 4
       x     y     z     l
   <int> <dbl> <dbl> <dbl>
 1     1  67.1 136.  151. 
 2     2  75.4 127.  148. 
 3     3 -11.1  38.9  40.6
 4     4  58.1 106.  121. 
 5     5  23.5 126.  128. 
 6     6  73.4 179.  193. 
 7     7  44.5 121.  129. 
 8     8 106.  131.  169. 
 9     9  32.5 140.  144. 
10    10 -27.7  82.7  87.8
# ... with 9,990 more rows

对我个人来说,它是非常清楚和优雅的。但你可以不同意这一点。

更新1

老实说,你的问题在性能方面也让我感兴趣。所以我决定去看看。 代码如下:

library(tidyverse)
library(microbenchmark)

n = 1000
df = tibble(
  x = 1:n,
  y = x + rnorm(n, mean=50, sd=50),
  z = x + y + rnorm(n, mean=50, sd=50)
)

f = function(data) sqrt(data$x^2+data$y^2+data$z^2)

f1 = function(df){
  df %>% nest(data = c(x:z)) %>% 
    mutate(l = map(data, f)) %>% 
    unnest(c(data, l))
}
f1(df)

f2 = function(df){
  df = df %>% mutate(l=NA)
  for(r in 1:nrow(df)){
    row = df[r, ]
    df$l[r] = f(row)
  }
  df
}
f2(df)


f3 = function(df){
  res = df %>% 
    split(., .$x) %>% 
    lapply(., f)
  df %>% bind_cols(l = unlist(res))
}
f3(df)


ggplot2::autoplot(microbenchmark(f1(df), f2(df), f3(df), times=100))

结果如下: 我还需要添加其他内容并解释为什么tibble%>% nest%>% mutate (map)%>% unnest方案如此酷吗?

这篇关于更快/更好:循环遍历数据帧的每一行或将其拆分成一个长度为`nrow`,R的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆