我正在使用调查数据,我想计算一个数字序列在同一位置(所有数字)出现的次数。
作为一个例子,我定义了一个数字序列,依次为2,3或2,3,4,2-。
例如
v1 v2 v3 v4 v5
2 3 4 2 6
3 2 4 6 7
2 3 4 2 3
例如,我想接收输出
position freq
(2,3) (v1, v2) 2
(3,4) (v2, v3) 2
(2,3,4,2) (v1,v2,v3,v4) 2
(2,3,4) (v1, v2, v3) 1
(2,3,4,2,6) (v1,v2,v3, v4, v5) 1
(3,4,2) (v2,v3,v4) 2
(3,4,2,6) (v2, v3, v4, v5) 1
(4,2) (v3, v4) 2
(4,2,6) (v3, v4, v5) 1
(2,6) (v4, v5) 1
and so on
....
我该如何编写函数以返回所需的输出?
非常感谢
答案 0 :(得分:0)
如果我理解正确,那么问题包括两个部分:
v1
至v5
(称为 position )与2、3、4或5个连续的 列的所有组合,即(v1, v2)
,(v2, v3)
,...,(v4, v5)
,(v1, v2, v3)
,...,(v2, v3, v4, v5)
和(v1, v2, v3, v4, v5)
。这可以通过将交叉连接和聚合结合在非等价连接中来解决:
library(data.table)
# read data
ds <- fread("
v1 v2 v3 v4 v5
2 3 4 2 6
3 2 4 6 7
2 3 4 2 3
")
library(data.table)
cols <- names(ds)
n <- length(cols)
# create all possible combinations of consecutive positions by
# cross joining of row id x sequence length x start position
vi <- CJ(rn = 1:nrow(ds), len = 2:5, start = 1:n)[
# compute end positions
, end := start + len - 1L][
# remove impossible end positions
end <= n]
# coerce to data.table, append row id, reshape from wide to long format
dl <- melt(setDT(ds)[, rn := .I], id.vars = "rn", variable.name = "pos",
variable.factor = TRUE)[
# use factor levels = column number
, pos := as.integer(pos)][]
# non-equi inner join and aggregate over join parameters
result <- dl[vi, on = .(rn, pos >= start, pos <= end),
.(rn, values = toString(value), position = toString(cols[x.pos])),
by = .EACHI, nomatch = 0L][
# count by values and positions
, .(freq = .N), by = .(values, position)]
# reorder result
result[order(nchar(values), values)]
values position freq 1: 2, 3 v1, v2 2 2: 2, 3 v4, a5 1 3: 2, 4 v2, v3 1 4: 2, 6 v4, a5 1 5: 3, 2 v1, v2 1 6: 3, 4 v2, v3 2 7: 4, 2 v3, v4 2 8: 4, 6 v3, v4 1 9: 6, 7 v4, a5 1 10: 2, 3, 4 v1, v2, v3 2 11: 2, 4, 6 v2, v3, v4 1 12: 3, 2, 4 v1, v2, v3 1 13: 3, 4, 2 v2, v3, v4 2 14: 4, 2, 3 v3, v4, a5 1 15: 4, 2, 6 v3, v4, a5 1 16: 4, 6, 7 v3, v4, a5 1 17: 2, 3, 4, 2 v1, v2, v3, v4 2 18: 2, 4, 6, 7 v2, v3, v4, a5 1 19: 3, 2, 4, 6 v1, v2, v3, v4 1 20: 3, 4, 2, 3 v2, v3, v4, a5 1 21: 3, 4, 2, 6 v2, v3, v4, a5 1 22: 2, 3, 4, 2, 3 v1, v2, v3, v4, a5 1 23: 2, 3, 4, 2, 6 v1, v2, v3, v4, a5 1 24: 3, 2, 4, 6, 7 v1, v2, v3, v4, a5 1 values position freq
首先,我们需要确定5个 position 列v1
至v5
与2、3、4或5个连续的所有可能组合列。
这是通过交叉连接可能长度的向量(即列数)和可能的起始位置的向量来实现的。然后,计算终点位置。不可能的终端位置(即不存在的列)将被删除。
CJ(len = 2:5, start = 1:n)[
# compute end positions
, end := start + len - 1L][
# remove impossible end positions
end <= n]
len start end
1: 2 1 2
2: 2 2 3
3: 2 3 4
4: 2 4 5
5: 3 1 3
6: 3 2 4
7: 3 3 5
8: 4 1 4
9: 4 2 5
10: 5 1 5
在随后的联接中,我们需要为ds
的每一行查找以上位置。因此,行号可以已经包含在交叉联接中。
vi <- CJ(rn = 1:nrow(ds), len = 2:5, start = 1:n)[
, end := start + len - 1L][
end <= n]
然后,ds
使用melt()
从宽格式改成长格式,结果是
dl
rn pos value 1: 1 1 2 2: 2 1 3 3: 3 1 2 4: 1 2 3 5: 2 2 2 6: 3 2 3 7: 1 3 4 8: 2 3 4 9: 3 3 4 10: 1 4 2 11: 2 4 6 12: 3 4 2 13: 1 5 6 14: 2 5 7 15: 3 5 3
列名将转换为整数位置,并且在重塑之前已添加行ID。
现在,所有准备工作都已完成,我们可以执行计算的中心部分,即非等价内部联接。这样,我们在dl
中找到与rn
匹配的条目,并且实际位置pos
在可能组合的给定范围[start, end]
内。参数by = .EACHI
请求立即合并联接参数。 toString()
用作聚合函数。所以,
dl[vi, on = .(rn, pos >= start, pos <= end),
.(rn, values = toString(value), position = toString(cols[x.pos])),
by = .EACHI, nomatch = 0L]
收益
rn pos pos rn values position 1: 1 1 2 1 2, 3 v1, v2 2: 1 2 3 1 3, 4 v2, v3 3: 1 3 4 1 4, 2 v3, v4 4: 1 4 5 1 2, 6 v4, v5 5: 1 1 3 1 2, 3, 4 v1, v2, v3 6: 1 2 4 1 3, 4, 2 v2, v3, v4 7: 1 3 5 1 4, 2, 6 v3, v4, v5 8: 1 1 4 1 2, 3, 4, 2 v1, v2, v3, v4 9: 1 2 5 1 3, 4, 2, 6 v2, v3, v4, v5 10: 1 1 5 1 2, 3, 4, 2, 6 v1, v2, v3, v4, v5 11: 2 1 2 1 3, 2 v1, v2 12: 2 2 3 1 2, 4 v2, v3 13: 2 3 4 1 4, 6 v3, v4 14: 2 4 5 1 6, 7 v4, v5 15: 2 1 3 1 3, 2, 4 v1, v2, v3 16: 2 2 4 1 2, 4, 6 v2, v3, v4 17: 2 3 5 1 4, 6, 7 v3, v4, v5 18: 2 1 4 1 3, 2, 4, 6 v1, v2, v3, v4 19: 2 2 5 1 2, 4, 6, 7 v2, v3, v4, v5 20: 2 1 5 1 3, 2, 4, 6, 7 v1, v2, v3, v4, v5 21: 3 1 2 1 2, 3 v1, v2 22: 3 2 3 1 3, 4 v2, v3 23: 3 3 4 1 4, 2 v3, v4 24: 3 4 5 1 2, 3 v4, v5 25: 3 1 3 1 2, 3, 4 v1, v2, v3 26: 3 2 4 1 3, 4, 2 v2, v3, v4 27: 3 3 5 1 4, 2, 3 v3, v4, v5 28: 3 1 4 1 2, 3, 4, 2 v1, v2, v3, v4 29: 3 2 5 1 3, 4, 2, 3 v2, v3, v4, v5 30: 3 1 5 1 2, 3, 4, 2, 3 v1, v2, v3, v4, v5 rn pos pos rn values position
请注意,整数pos
的值将转换回原始列名。
在随后的聚合步骤中,确定唯一values
,position
对的出现次数。请注意,这两个操作是 chained 链接的,它们是data.table
语法的 piping 。
最后,在打印时方便地对行进行重新排序。
在非等额联接中使用列号范围可确保仅根据请求考虑连续的列。