将一行转换成combine,c()作为r中的向量,然后用向量计算余弦相似度
Convert a row into a combine, c() as a vector in r and then use vectors to calculate the cosine similarity
你好,我有一个非常大的数据框,它是一个部分:
v1 <- c('i1', 'i10', 'i11')
v2 <- c(0.11, 0.07, 0.114)
v3 <- c(0.07, 0.08, 0.03)
df <- data.frame(cbind(v1, v2, v3))
如何编写一些代码将每一行转换为组合向量,x <- c()
?
也就是说,我的预期输出应该是并且变量名称需要来自列 V1
:
i1 <- c(0.11014318, 0.07302843, 0.01360761, 0.10619829, 0.14513045)
i10 <- c(0.07360007, 0.08013833, 0.13104657, 0.13174247, 0.14256615)
i11 <- c(0.11418245, 0.03300573, 0.11425297, 0.13686428, 0.03367279)
将每一行转换为向量后,我需要计算这些向量之间的余弦相似度,这就是为什么我需要拆分每一行并将它们保存为具有第一列名称的向量的原因 V1
。
library(lsa)
cosine(i1, i10)
cosine(i1, i11)
cosine(i10, i11)
下面的问题
你好山姆。感谢您的帮助,但我不知道为什么在添加更多列 V4
和 V5
以及 ID 为 i12
的一行时它不起作用?非常感谢您的耐心等待和帮助。
data_matrix <- function(df){
data_matrix <- tail(t(df), -1) |>
sapply(as.numeric) |>
matrix(
nrow = ncol(df)-1,
ncol = nrow(df),
dimnames = list(
seq_len(nrow(df)-1), # rows
df[,1] # columns
)
)
}
v1 <- c('i1', 'i10', 'i11', 'i12')
v2 <- c(0.11, 0.07, 0.114, 0.67)
v3 <- c(0.07, 0.08, 0.03, 087)
v4 <- c(0.12, 0.13, 0.14, 0.18)
v5 <- c(0.19, 0.21, 0.22, 0.22)
df <- data.frame(cbind(v1, v2, v3, v4, v5))
df
data_matrix(df)
只是 returns 错误:
Error in matrix(sapply(tail(t(df), -1), as.numeric), nrow = ncol(df) - :
length of 'dimnames' [1] not equal to array extent
您可以使用 split
或 asplit
拆分行,使用 setNames
将列表元素的名称设置为第一列,然后使用 list2env
将列表的元素添加到全局环境中:
l <- setNames(split(df[-1], seq(nrow(df))), df[,1])
# $i1
# v2 v3
# 1 0.11 0.07
#
# $i10
# v2 v3
# 2 0.07 0.08
#
# $i11
# v2 v3
# 3 0.114 0.03
list2env(l, .GlobalEnv)
其他拆分选项包括 asplit
和 row
:
asplit(df[-1], 1)
split(df[-1], row(df[-1])[, 1])
as.list(as.data.frame(t(df[, -1])))
另一种方法是在每一行上使用 apply
,这样您就可以直接设置环境:
apply(df, 1, function(x) assign(x[1], tail(x, -1), envir = globalenv()))
不过我同意@danlooo 的评论:我想不出任何你想要这样做的理由。
编辑:如何计算余弦相似度矩阵(以下评论)
如果你想计算一个余弦相似度矩阵,最好从一个矩阵开始,而不是弄乱你的全局环境,然后必须进行可能很大的成对计算组合。
首先将数据设置为正确的格式,一个带有列名的数字矩阵,这些列名是数据框的第一列:
data_matrix <- tail(t(df), -1) |>
sapply(as.numeric) |>
matrix(
nrow = ncol(df) - 1,
ncol = nrow(df),
dimnames = list(
seq_len(ncol(df)-1), # rows
df[,1] # columns
)
)
data_matrix
# i1 i10 i11
# 1 0.11 0.07 0.114
# 2 0.07 0.08 0.030
那么计算余弦相似度就很简单了:
library(lsa)
cosine(data_matrix)
# i1 i10 i11
# i1 1.0000000 0.9595950 0.9525148
# i10 0.9595950 1.0000000 0.8283488
# i11 0.9525148 0.8283488 1.0000000
您可以使用 lapply()
遍历所有行并为您的 df
编制索引。
之后,您可以使用@Maël 的list2env
函数将列表中的元素保存到全局环境中。
setNames(lapply(1:nrow(df), function(x) df[x, -1]), df[, 1])
$i1
v2 v3
1 0.11 0.07
$i10
v2 v3
2 0.07 0.08
$i11
v2 v3
3 0.114 0.03
先前答案的另一种变体:
lapply(seq_len(nrow(df)), \(.) assign(df$v1[.], unlist(df[.,-1]), envir = .GlobalEnv))
也就是说,对于每一(lapply
)行(seq_len(nrow(df))
、\(.)
),将所有列直到第一列转换为向量(unlist(df[.,-1])
),然后 assign
这些向量到全局环境 (envir = .GlobalEnv
) 中的第一列字符串 (unlist(df[.,-1])
)。
更快,改进@SamR 解决方案(其中将 df
转换为数组,所有数字数据都变成字符):
list2env(setNames(apply(df[-1], 1, identity, simplify = FALSE), nm = df$v1), .GlobalEnv)
但不比@Maël 解决方案快
v1 <- paste0("i", 1:1e+3)
lapply(2:200, \(.) assign(paste0("v", .), rnorm(1e+3), envir = .GlobalEnv))
df <- do.call("data.frame", args = sapply(ls(pattern = "^v\d+$"), get, envir = .GlobalEnv, simplify = FALSE))
microbenchmark::microbenchmark(
list2env(setNames(as.list(as.data.frame(t(df[, -1]))), df[, 1]), .GlobalEnv),
list2env(setNames(asplit(df[-1], 1), df[, 1]), .GlobalEnv),
list2env(setNames(apply(df[-1], 1, identity, simplify = FALSE), nm = df$v1), .GlobalEnv),
check = "equal")
Unit: milliseconds
expr min lq mean median uq max neval
list2env(setNames(as.list(as.data.frame(t(df[, -1]))), df[, 1]), .GlobalEnv) 5.548269 5.731607 9.444446 5.864418 6.114002 37.83762 100
list2env(setNames(asplit(df[-1], 1), df[, 1]), .GlobalEnv) 7.421431 7.568999 9.336666 7.639897 7.800458 31.90791 100
list2env(setNames(apply(df[-1], 1, identity, simplify = FALSE), nm = df$v1), .GlobalEnv) 8.031275 8.201781 9.796997 8.332828 8.512478 34.35403 100
@Maël 的其他解决方案(使用 split(df[-1], seq(nrow(df)))
和 split(df[-1], row(df[-1])[, 1])
)和@benson23 setNames(lapply(1:nrow(df), function(x) df[x, -1]), df[, 1])
的解决方案产生 data.frame
输出而不是向量。
你好,我有一个非常大的数据框,它是一个部分:
v1 <- c('i1', 'i10', 'i11')
v2 <- c(0.11, 0.07, 0.114)
v3 <- c(0.07, 0.08, 0.03)
df <- data.frame(cbind(v1, v2, v3))
如何编写一些代码将每一行转换为组合向量,x <- c()
?
也就是说,我的预期输出应该是并且变量名称需要来自列 V1
:
i1 <- c(0.11014318, 0.07302843, 0.01360761, 0.10619829, 0.14513045)
i10 <- c(0.07360007, 0.08013833, 0.13104657, 0.13174247, 0.14256615)
i11 <- c(0.11418245, 0.03300573, 0.11425297, 0.13686428, 0.03367279)
将每一行转换为向量后,我需要计算这些向量之间的余弦相似度,这就是为什么我需要拆分每一行并将它们保存为具有第一列名称的向量的原因 V1
。
library(lsa)
cosine(i1, i10)
cosine(i1, i11)
cosine(i10, i11)
下面的问题
你好山姆。感谢您的帮助,但我不知道为什么在添加更多列 V4
和 V5
以及 ID 为 i12
的一行时它不起作用?非常感谢您的耐心等待和帮助。
data_matrix <- function(df){
data_matrix <- tail(t(df), -1) |>
sapply(as.numeric) |>
matrix(
nrow = ncol(df)-1,
ncol = nrow(df),
dimnames = list(
seq_len(nrow(df)-1), # rows
df[,1] # columns
)
)
}
v1 <- c('i1', 'i10', 'i11', 'i12')
v2 <- c(0.11, 0.07, 0.114, 0.67)
v3 <- c(0.07, 0.08, 0.03, 087)
v4 <- c(0.12, 0.13, 0.14, 0.18)
v5 <- c(0.19, 0.21, 0.22, 0.22)
df <- data.frame(cbind(v1, v2, v3, v4, v5))
df
data_matrix(df)
只是 returns 错误:
Error in matrix(sapply(tail(t(df), -1), as.numeric), nrow = ncol(df) - :
length of 'dimnames' [1] not equal to array extent
您可以使用 split
或 asplit
拆分行,使用 setNames
将列表元素的名称设置为第一列,然后使用 list2env
将列表的元素添加到全局环境中:
l <- setNames(split(df[-1], seq(nrow(df))), df[,1])
# $i1
# v2 v3
# 1 0.11 0.07
#
# $i10
# v2 v3
# 2 0.07 0.08
#
# $i11
# v2 v3
# 3 0.114 0.03
list2env(l, .GlobalEnv)
其他拆分选项包括 asplit
和 row
:
asplit(df[-1], 1)
split(df[-1], row(df[-1])[, 1])
as.list(as.data.frame(t(df[, -1])))
另一种方法是在每一行上使用 apply
,这样您就可以直接设置环境:
apply(df, 1, function(x) assign(x[1], tail(x, -1), envir = globalenv()))
不过我同意@danlooo 的评论:我想不出任何你想要这样做的理由。
编辑:如何计算余弦相似度矩阵(以下评论)
如果你想计算一个余弦相似度矩阵,最好从一个矩阵开始,而不是弄乱你的全局环境,然后必须进行可能很大的成对计算组合。
首先将数据设置为正确的格式,一个带有列名的数字矩阵,这些列名是数据框的第一列:
data_matrix <- tail(t(df), -1) |>
sapply(as.numeric) |>
matrix(
nrow = ncol(df) - 1,
ncol = nrow(df),
dimnames = list(
seq_len(ncol(df)-1), # rows
df[,1] # columns
)
)
data_matrix
# i1 i10 i11
# 1 0.11 0.07 0.114
# 2 0.07 0.08 0.030
那么计算余弦相似度就很简单了:
library(lsa)
cosine(data_matrix)
# i1 i10 i11
# i1 1.0000000 0.9595950 0.9525148
# i10 0.9595950 1.0000000 0.8283488
# i11 0.9525148 0.8283488 1.0000000
您可以使用 lapply()
遍历所有行并为您的 df
编制索引。
之后,您可以使用@Maël 的list2env
函数将列表中的元素保存到全局环境中。
setNames(lapply(1:nrow(df), function(x) df[x, -1]), df[, 1])
$i1
v2 v3
1 0.11 0.07
$i10
v2 v3
2 0.07 0.08
$i11
v2 v3
3 0.114 0.03
先前答案的另一种变体:
lapply(seq_len(nrow(df)), \(.) assign(df$v1[.], unlist(df[.,-1]), envir = .GlobalEnv))
也就是说,对于每一(lapply
)行(seq_len(nrow(df))
、\(.)
),将所有列直到第一列转换为向量(unlist(df[.,-1])
),然后 assign
这些向量到全局环境 (envir = .GlobalEnv
) 中的第一列字符串 (unlist(df[.,-1])
)。
更快,改进@SamR 解决方案(其中将 df
转换为数组,所有数字数据都变成字符):
list2env(setNames(apply(df[-1], 1, identity, simplify = FALSE), nm = df$v1), .GlobalEnv)
但不比@Maël 解决方案快
v1 <- paste0("i", 1:1e+3)
lapply(2:200, \(.) assign(paste0("v", .), rnorm(1e+3), envir = .GlobalEnv))
df <- do.call("data.frame", args = sapply(ls(pattern = "^v\d+$"), get, envir = .GlobalEnv, simplify = FALSE))
microbenchmark::microbenchmark(
list2env(setNames(as.list(as.data.frame(t(df[, -1]))), df[, 1]), .GlobalEnv),
list2env(setNames(asplit(df[-1], 1), df[, 1]), .GlobalEnv),
list2env(setNames(apply(df[-1], 1, identity, simplify = FALSE), nm = df$v1), .GlobalEnv),
check = "equal")
Unit: milliseconds
expr min lq mean median uq max neval
list2env(setNames(as.list(as.data.frame(t(df[, -1]))), df[, 1]), .GlobalEnv) 5.548269 5.731607 9.444446 5.864418 6.114002 37.83762 100
list2env(setNames(asplit(df[-1], 1), df[, 1]), .GlobalEnv) 7.421431 7.568999 9.336666 7.639897 7.800458 31.90791 100
list2env(setNames(apply(df[-1], 1, identity, simplify = FALSE), nm = df$v1), .GlobalEnv) 8.031275 8.201781 9.796997 8.332828 8.512478 34.35403 100
@Maël 的其他解决方案(使用 split(df[-1], seq(nrow(df)))
和 split(df[-1], row(df[-1])[, 1])
)和@benson23 setNames(lapply(1:nrow(df), function(x) df[x, -1]), df[, 1])
的解决方案产生 data.frame
输出而不是向量。