我正在使用R分析我的Web服务器日志:
data = read.table("/path/to/log", sep=" ")
这些日志包括最终用户IP地址和USER_ID(登录后).
我正在寻找比平时更活跃的用户,或者使用比平常更多的IP地址.
我现在可以通过USER_ID将R分组并计算记录:
counts <- ddply(data, .(data$user_id), nrow); names(counts) <- c("user_id", "freq"); print(counts[order(counts$freq),c(2,1)], row.names = FALSE); freq user_id 1 10171 40 7433 94 210 102 2043
但我还想添加一个GROUP_CONCAT(DISTINCT IP)的等价物,如SQL中所示,我也可以看到该用户的不同IP地址列表.
freq user_id ips 1 10171 192.168.0.1 40 7433 192.168.0.5,192.168.0.2 94 210 192.168.0.9 102 2043 192.168.0.1,192.168.0.3,192.168.0.8
在SQL中,它看起来像:
SELECT user_id, COUNT(id) AS freq, GROUP_CONCAT(DISTINCT ip SEPARATOR ",") AS ips FROM log_table GROUP BY user_id ORDER BY freq ASC;
这可能与aggregate()函数有关,但我现在还没想出来.
我们可以dplyr
.我们按'user_id'进行分组,然后将'freq'作为行数(n()
)和'ips'作为paste(unique(ip), collapse=', ')
(或我们toString
用作包装器).
library(dplyr) data %>% group_by(user_id) %>% summarise(freq= n(), ips= toString(unique(ip))) #not sure we wanted the nrow or `length` of `unique` 'ip' #if the latter is the case #summarise(freq=n_distinct(ip), ips = toString(unique(ip)))
如果我们想要一个base R
解决方案
do.call(data.frame, aggregate(ip~user_id, data, FUN= function(x) c(freq= length(unique(ip)), ips=toString(unique(ip))))
在data.table
我们能做到:
library(data.table) setDT(data) data[ , .N , by = user_id]
请注意,在最新版本data.table
(自提交cd756e2,2015-09-26,此处为安装说明)中,此计数操作已针对速度进行了优化(根据一些基准测试,应该大约快8倍).
对于后者,这将起作用:
data[ , paste(unique(ip), collapse = ","), by = user_id]
要同时获得两者:
data[ , .(freq = .N, ips = paste(unique(ip), collapse = ",")), by = user_id]
如果你想按频率对它进行排序,找出"最大的罪魁祸首"是谁:
data[ , .(freq = .N, ips = paste(unique(ip), collapse = ",")), by = user_id][order(-freq)]