R dplyr:使用自定义函数的按行操作

时间:2018-12-21 16:02:46

标签: r dplyr rowwise

在熊猫中,我经常使用以下自定义函数执行逐行操作:

df = pd.DataFrame({'v1': [1, 2, 3], 'v2': [3, 4, 6], 'v3': [3, 4, 5]})

def f(row):
    return(sum(row[["v1", "v3"]]) if row.v2 == 3 else 7)

df["new_col"] = df.apply(f, 1)

在dplyr中相当于什么?

请注意,函数f可能会使用许多变量,而不仅仅是v1-v3,因此我宁愿在调用函数时不要全部命名它们。

编辑:我目前在R中拥有的示例代码。在此解决方案中,我传递了代名词对象,我对此是否合适表示怀疑。

d <- tibble(v1 = c(1,2,3), v2 = c(3,4,6), v3 = c(3,4,5))

f <- function(row){
  if (row$v2 == 3) sum(something?) else 7
}

d %>% rowwise() %>% mutate(new_column = f(.data)) %>% ungroup()

edit2:预期输出。 (索引列不重要)

   v1  v2  v3  new_col
0   1   3   3        4
1   2   4   4        7
2   3   6   5        7

注意:我不是在寻找针对此特定问题的解决方案。我对将行传递给R / dplyr中的函数的一般方式感兴趣,就像在pandas中将apply()那样。

3 个答案:

答案 0 :(得分:1)

等效的dplyr代码将整个行作为数据帧传递给函数,可能是:

library(tidyverse)

df <- tibble(v1 = c(1, 2, 3), v2 = c(4, 5, 6), v3 = c(7, 8, 9))

f <- function(row){
  if (row$v2 == 3){
    return(sum(row$v1, row$v3))
  }else{
    return(7)
  }
}

df %>% 
  rowwise() %>% 
  do(row = as_data_frame(.)) %>%
  mutate(new_col = f(row)) %>% 
  unnest()

出局:

# A tibble: 3 x 4
  new_col    v1    v2    v3
    <dbl> <dbl> <dbl> <dbl>
1       4     1     3     3
2       7     2     4     4
3       7     3     6     5

答案 1 :(得分:1)

如果您有一组适用于此的列,那么我建议您的函数只关注单个向量,而不要关注单行框架。

library(dplyr)
d <- tibble(v1 = c(1,2,3), v2 = c(3,4,6), v3 = c(3,4,5))
f <- function(v1, v2, v3) ifelse(v2 == 3, v1 + v3, 7)
d %>% rowwise() %>% mutate(new_column = f(v1, v2, v3)) %>% ungroup()
# # A tibble: 3 x 4
#      v1    v2    v3 new_column
#   <dbl> <dbl> <dbl>      <dbl>
# 1     1     3     3          4
# 2     2     4     4          7
# 3     3     6     5          7

我防御性地使用了ifelse,“以防万一”它曾被用在行上的组上。如果您将该函数定义为

,它就可以正常工作
f <- function(v1, v2, v3) if (v2 == 3) v1+v3 else 7

实际上,如果您的实际逻辑并不复杂,那么这不需要rowwise(),因此速度会大大提高。 (但我不知道您的真正需求。)

替代:

d %>% mutate(new_column = purrr::pmap_dbl(list(v1,v2,v3), f))

答案 2 :(得分:0)

df %>% mutate(new_col=with(.,case_when(v2 != 3 ~ 7,v2 == 3 ~ (v1 + v3))))

输出

 v1 v2 v3 new_col
1  1  3  3       4
2  2  4  4       7
3  3  6  5       7