Передача имен столбцов в пользовательскую функцию внутри mutate_at - PullRequest
0 голосов
/ 28 сентября 2018

Я пытаюсь передать имена столбцов внутри моей пользовательской функции при использовании dplyr - mutate_at.У меня есть набор данных «dt» с тысячами столбцов, и я хотел бы выполнить изменение для некоторых из этих столбцов, но способом, который зависит от имени столбца

У меня есть этот фрагмент кода

Вариант 1:

relevantcols = c("A", "B", "C")
myfunc <- function(colname, x) {
   #write different logic per column name
}
dt%>%
  mutate_at(relevantcols, funs(myfunc(<what should i give?>,.)))

Я пытался подойти к проблеме по-другому, то есть путем перебора соответствующих протоколов и применения mutate_at для каждого из элементов вектора следующим образом

Вариант 2:

for (i in 1:length(relevantcols)){
  dt%>%
  mutate_at(relevantcols[i], funs(myfunc(relevantcols[i], .))
}

Я получаю имена столбцов в Варианте 2, но это в 10 раз медленнее, чем в Варианте 1. Можно ли каким-то образом получить имена столбцов в Варианте 1?

Добавление примера для болееясность

df = data.frame(employee=seq(1:5), Mon_channelA=runif(5,1,10), Mon_channelB=runif(5,1,10), Tue_channelA=runif(5,1,10),Tue_channelB=runif(5,1,10))
df
 employee Mon_channelA Mon_channelB Tue_channelA Tue_channelB
1        1     5.234383     6.857227     4.480943     7.233947
2        2     7.441399     3.777524     2.134075     6.310293
3        3     7.686558     8.598688     9.814882     9.192952
4        4     6.033345     5.658716     5.167388     3.018563
5        5     5.595006     7.582548     9.302917     6.071108
relevantcols = c("Mon_channelA", "Mon_channelB")
myfunc <- function(colname, x) {
#based on the channel and weekday, compare the data from corresponding column with  the same channel but different weekday and return T if higher else F
}
# required output
employee Mon_channelA Mon_channelB Tue_channelA Tue_channelB
1        1     T     F     4.480943     7.233947
2        2     T     F     2.134075     6.310293
3        3     F     F     9.814882     9.192952
4        4     T     T     5.167388     3.018563
5        5     F     T     9.302917     6.071108

Ответы [ 2 ]

0 голосов
/ 28 сентября 2018

Я оставил комментарий о типах данных, но предполагая, что это именно то, что вы ищете, вот подход, который я использую для решения подобных проблем.Я делаю это в, казалось бы, запутанном процессе изменения формы несколько раз, но он позволяет вам устанавливать переменные, которые вы пытаетесь сравнивать, без особого программирования.Я разобью его на куски.

library(tidyverse)

set.seed(928)
df <- data.frame(employee=seq(1:5), Mon_channelA=runif(5,1,10), Mon_channelB=runif(5,1,10), Tue_channelA=runif(5,1,10),Tue_channelB=runif(5,1,10))

Сначала я бы изменил его в длинную форму и разбил бы "Mon_channelA" и т. Д. На день и канал.Это позволяет использовать обозначение канала для сопоставления значений для сравнения.

df %>%
  gather(key, value, -employee) %>%
  separate(key, into = c("day", "channel"), sep = "_") %>%
  head()
#>   employee day  channel    value
#> 1        1 Mon channelA 2.039619
#> 2        2 Mon channelA 8.153684
#> 3        3 Mon channelA 9.027932
#> 4        4 Mon channelA 1.161967
#> 5        5 Mon channelA 3.583353
#> 6        1 Mon channelB 7.102797

Затем верните его в широкий формат, основанный на днях.Теперь у вас есть столбец для каждого дня для каждой комбинации сотрудника и канала.

df %>%
  gather(key, value, -employee) %>%
  separate(key, into = c("day", "channel"), sep = "_") %>%
  spread(key = day, value = value) %>%
  head()
#>   employee  channel      Mon      Tue
#> 1        1 channelA 2.039619 9.826677
#> 2        1 channelB 7.102797 7.388568
#> 3        2 channelA 8.153684 5.848375
#> 4        2 channelB 6.299178 9.452274
#> 5        3 channelA 9.027932 5.458906
#> 6        3 channelB 7.029408 7.087011

Затем проведите сравнение и снова увеличьте объем данных.Обратите внимание, что, поскольку в столбце value есть числовые значения, все становится числовым, а логические значения преобразуются в 1 или 0.

df %>%
  gather(key, value, -employee) %>%
  separate(key, into = c("day", "channel"), sep = "_") %>%
  spread(key = day, value = value) %>%
  mutate(Mon = Mon > Tue) %>%
  gather(key = day, value = value, Mon, Tue) %>%
  head()
#>   employee  channel day value
#> 1        1 channelA Mon     0
#> 2        1 channelB Mon     0
#> 3        2 channelA Mon     1
#> 4        2 channelB Mon     0
#> 5        3 channelA Mon     1
#> 6        3 channelB Mon     0

Последние несколько шагов - объединить день и канал обратно, чтобы сделатьнадписи, как они были у вас, распространились обратно в широкоформатный формат и превратили все столбцы, начиная с "Mon", в логические элементы.

df %>%
  gather(key, value, -employee) %>%
  separate(key, into = c("day", "channel"), sep = "_") %>%
  spread(key = day, value = value) %>%
  mutate(Mon = Mon > Tue) %>%
  gather(key = day, value = value, Mon, Tue) %>%
  unite("variable", day, channel) %>%
  spread(key = variable, value = value) %>%
  mutate_at(vars(starts_with("Mon")), as.logical)
#>   employee Mon_channelA Mon_channelB Tue_channelA Tue_channelB
#> 1        1        FALSE        FALSE     9.826677     7.388568
#> 2        2         TRUE        FALSE     5.848375     9.452274
#> 3        3         TRUE        FALSE     5.458906     7.087011
#> 4        4        FALSE        FALSE     8.854263     8.946458
#> 5        5        FALSE        FALSE     6.933054     8.450741

Создано в 2018-09-28 с помощью представьте пакет (v0.2.1)

0 голосов
/ 28 сентября 2018

Вы можете делать такие вещи, как:

L <- c("A","B")
df <- data.frame(A=rep(1:3,2),B=1:6,C=7:12)
df
#  A B  C
#1 1 1  7
#2 2 2  8
#3 3 3  9
#4 1 4 10
#5 2 5 11
#6 3 6 12

f <- function(x,y) x^y

df %>% mutate_at(L,funs(f(.,2)))
#  A  B  C
#1 1  1  7
#2 4  4  8
#3 9  9  9
#4 1 16 10
#5 4 25 11
#6 9 36 12
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...