r пометить разные значения для одного и того же пользователя в строке
У меня есть данные следующим образом:
userID <-c(1,1,1,2,2,2,3,3,3)
product <-c("a","a","a","b","b","c","a","b","c")
result <-c(0,0,0,0,0,0,0,0,0)
df<-data.frame(userID,product,result)
Я хочу заполнить результат 1, если у userID есть разные продукты, и 0, если у пользователя все такие же продукты.
так что мой заполненный вектор будет выглядеть так:
result<-c(0,0,0,1,1,1,1,1,1)
Я понятия не имею, как сделать это без обширного цикла, но я знаю, что должен быть более быстрый путь.
4 ответа
Решение
Вы могли бы использовать ave
от base R
df$result <- with(df, ave(as.character(product), userID,
FUN=function(x) length(unique(x)))>1) +0
df$result
[1] 0 0 0 1 1 1 1 1 1
Или, как предлагает @David Arenburg, вы можете использовать transform
и создайте новую переменную result
в пределах df
transform(df, result = (ave(as.character(product),
userID, FUN = function(x) length(unique(x)))>1)+0)
Или же
tbl <- rowSums(!!table(df[,-3]))>1
(df$userID %in% names(tbl)[tbl])+0
#[1] 0 0 0 1 1 1 1 1 1
Вот один из способов добиться этого
library(data.table)
setDT(df)[, result := as.integer(length(unique(product)) > 1), by = userID]
df
# userID product result
# 1: 1 a 0
# 2: 1 a 0
# 3: 1 a 0
# 4: 2 b 1
# 5: 2 b 1
# 6: 2 c 1
# 7: 3 a 1
# 8: 3 b 1
# 9: 3 c 1
Или же
library(dplyr)
df %>%
group_by(userID) %>%
mutate(result = as.integer(n_distinct(product) > 1))
Вы можете использовать пакеты data.table
или же dplyr
чтобы решить этот вид задачи "разделить-применить-объединить". Вот как вы могли бы сделать это с помощью data.table
:
library(data.table)
setDT(df) ## convert to the new format
df[, result:=as.integer(length(unique(product)) > 1), by=userID]
Вот мой:
# table of users x number_of_products
myTable <- table(userID, product)
# one line from there:
(result <- ifelse(rowSums(myTable!=0)==1, 0, 1)[userID])
1 1 1 2 2 2 3 3 3
0 0 0 1 1 1 1 1 1