我正在尝试计算源矢量和tibble中的比较矢量之间的Jaccard相似性。
首先,使用names_字段(字符串向量)创建一个tibble。使用dplyr的mutate,创建names_vec,列表列,其中每一行现在都是一个向量(向量的每个元素都是一个字母)。
然后,用jaccard_sim列创建一个新的tibble,用于计算Jaccard的相似度。
source_vec <- c('a', 'b', 'c')
df_comp <- tibble(names_ = c("b d f", "u k g", "m o c"),
names_vec = strsplit(names_, ' '))
df_comp_jaccard <- df_comp %>%
dplyr::mutate(jaccard_sim = length(intersect(names_vec, source_vec))/length(union(names_vec, source_vec)))
jaccard_sim中的所有值均为零。但是,如果我们运行这样的东西,我们会得到第一个条目的正确Jaccard相似度为0.2:
a <- length(intersect(source_vec, df_comp[[1,2]]))
b <- length(union(source_vec, df_comp[[1,2]]))
a/b
答案 0 :(得分:9)
您只需添加rowwise
df_comp_jaccard <- df_comp %>%
rowwise() %>%
dplyr::mutate(jaccard_sim = length(intersect(names_vec, source_vec))/
length(union(names_vec, source_vec)))
# A tibble: 3 x 3
names_ names_vec jaccard_sim
<chr> <list> <dbl>
1 b d f <chr [3]> 0.2
2 u k g <chr [3]> 0.0
3 m o c <chr [3]> 0.2
使用rowwise
,您可以获得使用mutate
时所期望的直观行为:“为每一行执行此操作”。
不使用rowwise
意味着你利用矢量化函数,这要快得多,这就是为什么它是默认值,但如果你不小心可能会产生意想不到的结果。
mutate
(或其他dplyr
函数)按行工作的印象是一种幻觉,因为你正在处理矢量化函数,事实上你总是在玩完整列
我将用几个例子来说明:
有时结果是相同的,使用矢量化函数,例如paste
:
tibble(a=1:10,b=10:1) %>% mutate(X = paste(a,b,sep="_"))
tibble(a=1:10,b=10:1) %>% rowwise %>% mutate(X = paste(a,b,sep="_"))
# # A tibble: 5 x 3
# a b X
# <int> <int> <chr>
# 1 1 5 1_5
# 2 2 4 2_4
# 3 3 3 3_3
# 4 4 2 4_2
# 5 5 1 5_1
有时候它会有所不同,其功能没有矢量化,例如max
:
tibble(a=1:5,b=5:1) %>% mutate(max(a,b))
# # A tibble: 5 x 3
# a b `max(a, b)`
# <int> <int> <int>
# 1 1 5 5
# 2 2 4 5
# 3 3 3 5
# 4 4 2 5
# 5 5 1 5
tibble(a=1:5,b=5:1) %>% rowwise %>% mutate(max(a,b))
# # A tibble: 5 x 3
# a b `max(a, b)`
# <int> <int> <int>
# 1 1 5 5
# 2 2 4 4
# 3 3 3 3
# 4 4 2 4
# 5 5 1 5
请注意,在这种情况下,您不应在现实生活中使用rowwise
,而是pmax
为此目的进行矢量化:
tibble(a=1:5,b=5:1) %>% mutate(pmax(a,b))
# # A tibble: 5 x 3
# a b `pmax(a, b)`
# <int> <int> <int>
# 1 1 5 5
# 2 2 4 4
# 3 3 3 3
# 4 4 2 4
# 5 5 1 5
相交是这样的函数,你给这个函数提供了一个包含向量和另一个向量的列表列,这两个对象没有交集。
答案 1 :(得分:8)
我们可以使用map
循环浏览list
library(tidyverse)
df_comp %>%
mutate(jaccard_sim = map_dbl(names_vec, ~length(intersect(.x,
source_vec))/length(union(.x, source_vec))))
# A tibble: 3 x 3
# names_ names_vec jaccard_sim
# <chr> <list> <dbl>
#1 b d f <chr [3]> 0.2
#2 u k g <chr [3]> 0.0
#3 m o c <chr [3]> 0.2
优化map
个功能。以下是稍大一点的数据集的system.time
df_comp1 <- df_comp[rep(1:nrow(df_comp), 1e5),]
system.time({
df_comp1 %>%
rowwise() %>%
dplyr::mutate(jaccard_sim = length(intersect(names_vec, source_vec))/length(union(names_vec, source_vec)))
})
#user system elapsed
# 25.59 0.05 25.96
system.time({
df_comp1 %>%
mutate(jaccard_sim = map_dbl(names_vec, ~length(intersect(.x,
source_vec))/length(union(.x, source_vec))))
})
#user system elapsed
# 13.22 0.00 13.22