我有一个示例数据框
df <- data.frame(cust = sample(1:100, 1000, TRUE),
channel = sample(c("WEB", "POS"), 1000, TRUE))
我试图改变
get_channels <- function(data) {
d <- data
if(unique(d) %>% length() == 2){
d <- "Both"
} else {
if(unique(d) %>% length() < 2 && unique(d) == "WEB") {
d <- "Web"
} else {
d <- "POS"
}
}
return(d)
}
这没有问题,在小型数据帧上,它根本不需要时间。
start.time <- Sys.time()
df %>%
group_by(cust) %>%
mutate(chan = get_channels(channel)) %>%
group_by(cust) %>%
slice(1) %>%
group_by(chan) %>%
summarize(count = n()) %>%
mutate(perc = count/sum(count))
end.time <- Sys.time()
time.taken <- end.time - start.time
time.taken
时差0.34602秒
然而,当数据框变得相当大时,例如,大约> 1000000或更多cust
,我的基本if/else
fx需要更多,更多更长
如何简化此功能以使其更快地运行?
答案 0 :(得分:5)
您应该使用data.table。
setDT(df)
t1 = Sys.time()
df = df[ , .(channels = ifelse(uniqueN(channel) == 2, "both", as.character(channel[1]))), by = .(cust)]
> Sys.time() - t1
Time difference of 0.00500083 secs
> head(df)
cust channels
1: 37 both
2: 45 both
3: 74 both
4: 20 both
5: 1 both
6: 68 both
答案 1 :(得分:3)
您可以使用类似的东西在基地R中执行此操作:
web_cust <- unique(df$cust[df$channel=="WEB"])
pos_cust <- unique(df$cust[df$channel=="POS"])
both <- length(intersect(web_cust, pos_cust))
web_only <- length(setdiff(web_cust, pos_cust))
pos_only <- length(setdiff(pos_cust, web_cust))
数据:强>
set.seed(1)
df <- data.frame(cust = sample(2e6, 1e7, TRUE),
channel = sample(c("WEB", "POS"), 1e7, TRUE),
stringsAsFactors = F)
答案 2 :(得分:1)
更快的dplyr
版本需要大约1/3的时间,但可能仍然比数据表版本慢。 uniqueN
借用@Kristoferson回答。
df %>%
group_by(cust) %>%
summarize(chan = if_else(uniqueN(channel) == 2, "Both", as.character(channel[1]))) %>%
group_by(chan) %>%
summarize(n = n() ) %>%
mutate(perc = n /sum(n))
此外,通过优化您的功能可以显着改善您的原始状态:
get_channels <- function(data) {
ud <- unique(data)
udl <- length(ud)
if(udl == 2) {
r <- "Both"
} else {
if(udl < 2 && ud == "WEB") {
r <- "Web"
} else {
r <- "POS"
}
}
return(r)
}
答案 3 :(得分:1)
还有一些时间......
我在dplyr
和data.table
中尝试了三种不同的选择:(1)ifelse
(请参阅@ Kristofersen的回答),(2)if
/ {{1} (因为else
长度为1),(3)向量索引。不出所料,主要区别在于test
和dplyr
之间,而不是替代1-3之间。
对于1000个客户,data.table
的速度提高了约7倍。对于10000个客户来说,速度提高了约30倍。对于1e6客户,我只测试了data.table
,而不是替代品之间的差异。
data.table