Как эффективно вернуть все имена столбцов в записях 1 м, когда выполняются определенные условия - PullRequest
0 голосов
/ 29 декабря 2018

Обновлены фиктивные данные и фиктивный код - извинения, я предположил, что мой вопрос прост, и вы могли бы посоветовать лучший способ без воспроизводимого примера.

dummy<-data.frame(prodA=c(0,0,0,1,1,0,0,1),
              prodB=c(0,0,1,1,0,1,1,0),
              prodC=c(1,1,1,0,0,0,0,1))

dummy[,4:6]<-dummy[,1:3]

for (j in (1:nrow(dummy))){
    for (i in 4:6){
            dummy[j,i]<-ifelse(dummy[j,i]==1,colnames(dummy[i]),"")}
}
dummy2<-dummy[,4:6]
dummy$NewProds<-apply(dummy2,1,paste,collapse="") 
dummy$NewProds<-gsub(".1","//",dummy$NewProds)

Моя вторая попытка выглядит так:

prods<-dummy[,1:3]
prods[,4:6]<-dummy[,1:3]
for (i in 4:6){
    prods[,i]<-colnames(prods[i-3])
}

prods[,7:9]<-prods[,4:6]
#works, but I will need multiple ifs for this to work, suggesting this
#won't be very efficient
prods[,10]<-ifelse(prods[,1]==1,prods[,4],"")

Исходное сообщение следует: Я играю с набором рекомендаций по продуктам Сантандера от Kaggle.Я определил, какие продукты были приобретены от одного месяца к другому.Это означает, что у меня есть 23 столбца 1 (когда добавлен новый продукт) и 0 (когда нет).Я создал следующий код, чтобы вернуть имя столбца при покупке продукта.Он отлично работает на выборке из 6 строк, но он работает вечно, когда я пробую это на 48 000 клиентов, которые изменились, не говоря уже о миллионе в наборе данных.

Есть ли другой способ сделать это?

df2[,99:122]<-df2[,72:95]

for (j in (1:nrow(df2))){
    for (i in 99:122){
            df2[j,i]<-ifelse(df2[j,i]==1,colnames(df2[i]),"")}
}
df22<-df2[,99:122]
df2$NewProds<-apply(df22,1,paste,collapse="") 
df2$NewProds<-gsub("change.1","//",df2$NewProds)

Я подумал, что проблема в том, что я смотрю на каждую переменную и поэтому начал с другого подхода, согласно которому я бы взял пару версий данных, а затем сделал бы переменную if равной 1, а затем взял бы имя.Однако я не мог заставить это работать, и я думаю, что я прихожу к той же самой проблеме.

#copy a bunch of 1's and 0's
prods<-df2[,72:95]
#repeat and overwrite with colnames
prods[,25:48]<-df2[,72:95]
for (i in 25:48){
    prods[,i]<-colnames(prods[i-24])
}
prods[,49:72]<-prods[,25:48]
#attempt to only populate colnames if it was originally a 1 - doesn't work
prod[,49]<-ifelse(prod[,1]==1,prod[,25],"")

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

Ответы [ 2 ]

0 голосов
/ 30 декабря 2018

Использование apply, как показано @AndersEllernBilgrau, является одним из очевидных способов сделать это, но оно будет медленным для наборов данных со многими строками.

dummy[["NewProds"]] <- do.call(
    paste,
    c(mapply(ifelse,
             dummy,
             names(dummy),
             MoreArgs = list(no = ""),
             SIMPLIFY = FALSE),
      sep = "//"))

немного сложнее, но это будетбыть намного быстрее:

library(microbenchmark)

n <- 10000
dummy <- data.frame(prodA = rep(c(0,0,0,1,1,0,0,1), n),
                    prodB = rep(c(0,0,1,1,0,1,1,0), n),
                    prodC = rep(c(1,1,1,0,0,0,0,1), n))

microbenchmark(
    do.call = do.call(
        paste,
        c(mapply(ifelse,
                 dummy,
                 names(dummy),
                 MoreArgs = list(no = ""),
                 SIMPLIFY = FALSE),
          sep = "//")),
    apply = apply(
        dummy == 1,
        1,
        function(x) paste0(names(which(x)), collapse = "//")
    ))
## Unit: milliseconds
##     expr       min        lq      mean   median       uq      max neval cld
##  do.call  63.92695  65.44777  72.07261  67.8667  73.3850 184.5151   100  a 
##    apply 296.81323 364.31947 404.71894 397.0927 443.7223 683.3892   100   b
0 голосов
/ 29 декабря 2018

Без данных мне трудно понять, что именно вы хотите сделать.Однако пара (почти) определенна:

  • Возможно, вам не нужны for петли.
  • Вы должны использовать векторизованные функции R, набор данных не является что большой

Используя некоторые игрушечные данные, делает ли следующее то, что вы хотите?

d <- 23
n <- 46e3

# Simulate some toy data
df <- data.frame(matrix(rbinom(d*n, 1, 0.1), n, d),
                 row.names = paste0("row", 1:n))
head(df)
      X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23
row1  0  0  0  0  0  0  0  1  0   0   0   0   0   0   0   1   0   0   0   0   0   0   0
row2  1  0  0  0  0  0  0  0  0   0   0   0   0   0   0   0   0   0   0   0   0   0   0
row3  0  0  0  0  0  0  0  1  0   0   0   0   0   0   0   0   0   0   0   1   0   0   0
row4  0  0  0  1  0  0  0  0  0   0   1   0   0   0   0   0   0   0   0   1   0   0   0
row5  0  0  0  0  0  0  1  0  0   0   0   0   0   0   1   0   0   0   0   0   0   0   0
row6  0  0  0  1  0  0  0  0  0   0   0   0   0   0   0   0   0   1   0   0   1   0   0



# Paste together the colnames of all non-zero rows
res <- apply(df == 1, 1, function(x) paste0(names(which(x)), collapse = "-"))
head(res)
#    row1         row2         row3         row4         row5         row6 
#"X8-X16"         "X1"     "X8-X20" "X4-X11-X20"     "X7-X15" "X4-X18-X21" 

Т.е. res здесь есть символьный вектор длины nс именами столбцов каждой строки, соответствующей 1 записи, вставленной вместе (с разделителем -).Это как минимум то, что мне кажется, что ваш код делает концептуально.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...