【发布时间】:2020-09-23 19:05:36
【问题描述】:
我已经搜索过这个问题的答案并找到了类似的答案(Count number of rows within each group、count unique combinations of variable values in an R dataframe column、R count occurrences of an element by groups),但没有一个能解决我的特定问题。
我有一个包含变量 year、ID 和 code 的数据框。每个人都有一个ID,并且在(可能)多个years 的过程中可以有多个code 值。
df = data.frame(ID = c(1,1,1,1, 2,2,2, 3, 4,4,4,4,4,4,4,4, 5,5,5),
year = c(2018, 2018, 2020, 2020,
2020, 2020, 2020,
2011,
2019, 2019, 2019, 2019, 2020, 2020, 2020, 2020,
2018, 2019, 2020),
code = c("A", "B", "C", "D",
"A", "B", "Q",
"G",
"A", "B", "Q", "G", "C", "D", "T", "S",
"S", "Z", "F")
)
df
ID year code
1 1 2018 A
2 1 2018 B
3 1 2020 C
4 1 2020 D
5 2 2020 A
6 2 2020 B
7 2 2020 Q
8 3 2011 G
9 4 2019 A
10 4 2019 B
11 4 2019 Q
12 4 2019 G
13 4 2020 C
14 4 2020 D
15 4 2020 T
16 4 2020 S
17 5 2018 S
18 5 2019 Z
19 5 2020 F
我想要的是另一个数据框,给出code 的两个不同值在ID 和year 的分组内共同出现的次数(在本例中,A 和 B 共同出现 3 次,和 A 和 C 共出现 0 次),然后我将用于网络分析。
到目前为止,我有这样的语法:
1:制作数据的宽版本
library(tidyverse)
wide = df %>%
group_by(year, ID) %>%
mutate(row = row_number()) %>%
ungroup() %>%
pivot_wider(
id_cols = c(ID, year),
names_from = row,
names_prefix = "code_",
values_from = code
)
2:制作节点列表
nodes = distinct(df, code) %>% rowid_to_column("id")
3:制作边缘列表
#edge list needs to be three vars: source, dest, and weight
# source and dest are simply code names that (potentially) co-occur in the same year for an ID
# weight is the number of times the codes co-occurred in the same year for each ID.
#all combinations of two codes
edges = combn(x = nodes$code, m = 2 ) %>%
t() %>%
as.data.frame()
colnames(edges) = c("source", "dest")
edges$weight = NA_integer_
#oh, no! a for() loop! a coder's last ditch effort to make something work
for(i in 1:nrow(edges)){
source = edges$source[i]
dest = edges$dest[i]
#get the cases with the first code of interest
temp = df %>%
filter( code == source ) %>%
select(ID, year)
#get the other codes that occurred for that ID in that year
temp = left_join(temp,
wide,
by = c("ID", "year"))
#convert to a logical showing if the other codes are the one I want
temp = temp %>% mutate_at(vars(starts_with("code_")),
function(x){ x == dest }
)
#sum the number of times `source` and `dest` co-occurred
temp$dest = temp %>% select(starts_with("code_")) %>% rowSums(., na.rm=TRUE)
edges$weight[i] = sum(temp$dest, na.rm = TRUE)
}
编辑以添加结果:
结果:
edges
source dest weight
1 A B 3
2 A C 0
3 A D 0
4 A Q 2
5 A G 1
6 A T 0
7 A S 0
8 A Z 0
9 A F 0
10 B C 0
11 B D 0
12 B Q 2
13 B G 1
14 B T 0
15 B S 0
16 B Z 0
17 B F 0
18 C D 2
19 C Q 0
20 C G 0
21 C T 1
22 C S 1
23 C Z 0
24 C F 0
25 D Q 0
26 D G 0
27 D T 1
28 D S 1
29 D Z 0
30 D F 0
31 Q G 1
32 Q T 0
33 Q S 0
34 Q Z 0
35 Q F 0
36 G T 0
37 G S 0
38 G Z 0
39 G F 0
40 T S 1
41 T Z 0
42 T F 0
43 S Z 0
44 S F 0
45 Z F 0
这给了我想要的(一个数据框显示 A 和 B 共出现 3 次,A 和 C 共出现 0 次,A 和 D 共出现 0 次,A 和 G 共出现 1 次,A和 Q 共出现 2 次,等等...)。所以这是可行的,但即使是这个小例子也需要一两秒钟。我的真实数据集是约 3,000,000 次观察。我让它运行了一段时间,但停下来才发现它已经完成了大约 1%。
有没有更好/更快的方法来做到这一点?
【问题讨论】:
-
你能显示预期的输出吗
-
同一
code能否针对特定的id和year组合出现多次?
标签: r network-analysis