Условная вставка значений из одного столбца в другой в R - PullRequest
6 голосов
/ 06 августа 2020

Я борюсь с некоторыми вещами, связанными с данными, которые, как мне кажется, должно быть легко решить (с lapply или что-то в этом роде), но я просто не могу заставить его работать (и я, очевидно, чертовски ржавый из этого материала). Я работаю с набором веб-данных, структурированным следующим образом:

 df <- data.frame("ID" = c(1, 1, 1, 2, 3, 3),  
                 "URL_visit" = c(1, 2, 3, 1, 1, 2), # e.g. customer ID #1 has visited 3 pages
                 "URL_name" = c("home", "login", "product_page", "home", "home", "product_page"),
                 "duration" = c(14, 40, 233, 8, 76, 561),
                 "home" = c(1, 0, 0, 1, 1, 0),
                 "login" = c(0, 1, 0, 0, 0, 0), 
                 "product_page" = c(0, 0, 1, 0, 0, 1)
                   )

Итак, в основном поле идентификатора клиента, номер для каждого события для каждого клиента, URL-адрес, который они посетили в этом событии, за которым следует столбец для каждый URL-адрес с индикатором (1/0), посетил ли клиент этот конкретный URL-адрес в этом событии.

Моя цель - получить фрагмент кода, который заменяет индикаторы 1/0 продолжительностью, если совпадение ( 1) найден и сохраняет 0, если нет. Другими словами:

  • (1) Построчно проверяет значения столбцов URL (в моем примере столбцы 5: 7, также известные как home, login, product_page. У меня также есть вектор со столбцом имена) в 1 или 0
  • (2) Если он находит 1, вставляет значение из столбца duration , в противном случае 0.

Либо замена всех текущих (0/1) значений в столбцах URL-адресов продолжительностью, где это применимо, или создание нового набора столбцов (например, "home_duration") работает для меня.

Пример решения вручную:

df %<>% dplyr::mutate(home_duration = if_else(home == 1, duration, 0))

Но, конечно, моя цель - автоматизировать это и провести это для всего набора URL-столбцов (передача вектора с именами столбцов URL).

Помощь очень приветствуется ! Спасибо! :)

Ответы [ 4 ]

5 голосов
/ 06 августа 2020

Вы можете попробовать повернуть его на длинную, сделав вашу трансформацию, а затем снова развернуть обратно.

library(dplyr)
library(tidyr)

url_col_names <- c("home", "login", "product_page")

df %>% 
  pivot_longer(url_col_names, names_to = "url", values_to = "url_duration") %>% 
  mutate(url_duration = url_duration * duration) %>% 
  pivot_wider(names_from = "url", values_from = "url_duration")
# A tibble: 6 x 7
     ID URL_visit URL_name     duration  home login product_page
  <dbl>     <dbl> <fct>           <dbl> <dbl> <dbl>        <dbl>
1     1         1 home               14    14     0            0
2     1         2 login              40     0    40            0
3     1         3 product_page      233     0     0          233
4     2         1 home                8     8     0            0
5     3         1 home               76    76     0            0
6     3         2 product_page      561     0     0          561

Другой способ, возможно, более простой, - это сделать это.

df %>% 
  mutate(across(any_of(url_col_names), ~ . * duration))
  ID URL_visit     URL_name duration home login product_page
1  1         1         home       14   14     0            0
2  1         2        login       40    0    40            0
3  1         3 product_page      233    0     0          233
4  2         1         home        8    8     0            0
5  3         1         home       76   76     0            0
6  3         2 product_page      561    0     0          561

Edit

С другой стороны, я полагаю, вы создали эти индикаторные переменные? Если вы просто надеетесь заменить их, возможно, вам не потребуется создавать их для начала. Вы можете просто pivot_wider() с самого начала.

Это предполагает, что ваши столбцы ID и URL_visit образуют уникальную комбинацию строк.

df2 <- df[, 1:4]

df2 %>% 
  pivot_wider(names_from = "URL_name", values_from = "duration", values_fill = 0)
3 голосов
/ 06 августа 2020

Подобно @Adam, across() может использоваться с ifelse() для вычисления переменных с использованием структуры, подобной упомянутой пользователем:

library(dplyr)
#Data
df <- data.frame("ID" = c(1, 1, 1, 2, 3, 3),  
                 "URL_visit" = c(1, 2, 3, 1, 1, 2), # e.g. customer ID #1 has visited 3 pages
                 "URL_name" = c("home", "login", "product_page", "home", "home", "product_page"),
                 "duration" = c(14, 40, 233, 8, 76, 561),
                 "home" = c(1, 0, 0, 1, 1, 0),
                 "login" = c(0, 1, 0, 0, 0, 0), 
                 "product_page" = c(0, 0, 1, 0, 0, 1)
)
#Code
df %>%
  mutate(across(c(home:product_page), ~ ifelse(.==1, duration, .)))

Вывод:

  ID URL_visit     URL_name duration home login product_page
1  1         1         home       14   14     0            0
2  1         2        login       40    0    40            0
3  1         3 product_page      233    0     0          233
4  2         1         home        8    8     0            0
5  3         1         home       76   76     0            0
6  3         2 product_page      561    0     0          561

Кроме того, если необходимо сохранить исходные переменные, этот код может помочь:

df %>%
  mutate(across(c(home:product_page),.fns = list(duration = ~ ifelse(.==1, duration, .)) ))

Вывод:

  ID URL_visit     URL_name duration home login product_page home_duration login_duration
1  1         1         home       14    1     0            0            14              0
2  1         2        login       40    0     1            0             0             40
3  1         3 product_page      233    0     0            1             0              0
4  2         1         home        8    1     0            0             8              0
5  3         1         home       76    1     0            0            76              0
6  3         2 product_page      561    0     0            1             0              0
  product_page_duration
1                     0
2                     0
3                   233
4                     0
5                     0
6                   561
3 голосов
/ 06 августа 2020

Простое умножение должно помочь (это эквивалентно решению @Adam tidyverse выше, но в базе R)

url_col_names <- c('home','login','product_page')    
df$duration * df[,url_col_names] -> df[,url_col_names]

Чтобы переименовать столбцы, вы можете сделать:

names(df)[names(df) %in% url_col_names] <- paste0(url_col_names, '_', 'duration')
          
2 голосов
/ 06 августа 2020

Вот решение Data.table:

library(data.table)
url_values <- unique(df$URL_name)
for (val in url_values){
  setDT(df)[,home := ifelse(home == 1, duration, home)]
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...