R dplyr: Операции со строками с использованием пользовательских функций
В пандах я часто выполняю построчные операции с пользовательской функцией, подобной этой:
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, поэтому я бы предпочел не называть их всех при вызове функции.
edit: Пример кода того, что у меня есть в настоящее время в 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, как apply() в пандах.
3 ответа
Эквивалентный код 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
Если у вас есть хорошо укомплектованный набор столбцов, к которым это применимо, тогда я предлагаю, чтобы ваша функция касалась только отдельных векторов, а не однорядных фреймов.
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))
df %>% mutate(new_col=with(.,case_when(v2 != 3 ~ 7,v2 == 3 ~ (v1 + v3))))
Ouput
v1 v2 v3 new_col
1 1 3 3 4
2 2 4 4 7
3 3 6 5 7