48k 患者数据与预测变量之间的余弦相似性(患者相似性度量)
cosine similarity(patient similarity metric) between 48k patients data with predictive variables
我必须计算 R 中 48k 患者数据与一些预测变量之间的余弦相似性(患者相似性度量)。这是等式:PSM(P1,P2) = P1.P2/ ||P1|| ||P2||
其中 P1 和 P2 是对应于两个不同患者的预测向量,例如 P1 指数患者和 P2 将与指数 (P1) 进行比较,最后将计算成对患者相似性度量 PSM(P1,P2)。
这个过程将对所有 48,000 名患者进行。
我在 .csv 文件中添加了 300 名患者的示例数据集。请在此处找到示例数据集。https://1drv.ms/u/s!AhoddsPPvdj3hVTSbosv2KcPIx5a
首先要做的事:您可以在以下任一帖子中找到更严格的余弦相似度处理方法:
- Find cosine similarity between two arrays
- Creating co-occurrence matrix
现在,您显然在输入中混合了多种数据类型,至少
- 十进制
- 整数
- 分类
我怀疑某些整数值是布尔值或其他分类值。通常,如果您想将它们用作相似度计算的输入,则由您将它们转换为连续的数值向量。例如,录取类型 ELECTIVE
和 EMERGENCY
之间的 距离 是多少?它是名义变量还是顺序变量?我只会对我认为是数值因变量的列建模。
此外,您做了哪些工作来确保您的某些专栏与其他专栏不相关?只要对数据科学和生物医学术语有一点了解,这似乎很可能以下都是相关的:
diasbp_max
, diasbp_min
, meanbp_max
, meanbp_min
, sysbp_max
and sysbp_min
我建议去打印店订购 psm_pairs.pdf
的海报尺寸打印件。 :-) 你的眼睛更擅长检测变量之间有意义的(但非线性的)依赖关系。在您的相似性计算中,包括对同一基本现象的多次测量可能会过度加权该现象。不要忘记你可以推导像
这样的变量
diasbp_rage <- diasbp_max - diasbp_min
现在,我不是特别擅长线性代数,所以我从 lsa
文本分析包中导入一个余弦相似度函数。我很乐意看到 你 将你问题中的公式写成 R 函数。我会写它来比较一行与另一行,并使用两个嵌套的应用循环来获取所有比较。希望我们会得到相同的结果!
计算相似度后,我尝试找到两个最不相似的遭遇。
由于您处理的行数相对较大,因此您需要比较各种算法方法以提高效率。此外,您可以在具有多核和 lots RAM 的单台计算机上使用 SparkR/some other Hadoop solution on a cluster, or the parallel 程序包。我不知道我提供的解决方案是否是线程安全的。
想想看,对于一组 100 万名患者的遭遇,单独的换位(正如我实现的那样)可能在计算上是昂贵的。总的来说,(如果我没记错的话)随着输入中行数的增加,性能可能会呈指数下降。
library(lsa)
library(reshape2)
psm_sample <- read.csv("psm_sample.csv")
row.names(psm_sample) <-
make.names(paste0("patid.", as.character(psm_sample$subject_id)), unique = TRUE)
temp <- sapply(psm_sample, class)
temp <- cbind.data.frame(names(temp), as.character(temp))
names(temp) <- c("variable", "possible.type")
numeric.cols <- (temp$possible.type %in% c("factor", "integer") &
(!(grepl(
pattern = "_id$", x = temp$variable
))) &
(!(
grepl(pattern = "_code$", x = temp$variable)
)) &
(!(
grepl(pattern = "_type$", x = temp$variable)
))) | temp$possible.type == "numeric"
psm_numerics <- psm_sample[, numeric.cols]
row.names(psm_numerics) <- row.names(psm_sample)
psm_numerics$gender <- as.integer(psm_numerics$gender)
psm_scaled <- scale(psm_numerics)
pair.these.up <- psm_scaled
# checking for independence of variables
# if the following PDF pair plot is too big for your computer to open,
# try pair-plotting some random subset of columns
# keep.frac <- 0.5
# keep.flag <- runif(ncol(psm_scaled)) < keep.frac
# pair.these.up <- psm_scaled[, keep.flag]
# pdf device sizes are in inches
dev <-
pdf(
file = "psm_pairs.pdf",
width = 50,
height = 50,
paper = "special"
)
pairs(pair.these.up)
dev.off()
#transpose the dataframe to get the
#similarity between patients
cs <- lsa::cosine(t(psm_scaled))
# this is super inefficnet, because cs contains
# two identical triangular matrices
cs.melt <- melt(cs)
cs.melt <- as.data.frame(cs.melt)
names(cs.melt) <- c("enc.A", "enc.B", "similarity")
extract.pat <- function(enc.col) {
my.patients <-
sapply(enc.col, function(one.pat) {
temp <- (strsplit(as.character(one.pat), ".", fixed = TRUE))
return(temp[[1]][[2]])
})
return(my.patients)
}
cs.melt$pat.A <- extract.pat(cs.melt$enc.A)
cs.melt$pat.B <- extract.pat(cs.melt$enc.B)
same.pat <- cs.melt[cs.melt$pat.A == cs.melt$pat.B ,]
different.pat <- cs.melt[cs.melt$pat.A != cs.melt$pat.B ,]
most.dissimilar <-
different.pat[which.min(different.pat$similarity),]
dissimilar.pat.frame <- rbind(psm_numerics[rownames(psm_numerics) ==
as.character(most.dissimilar$enc.A) ,],
psm_numerics[rownames(psm_numerics) ==
as.character(most.dissimilar$enc.B) ,])
print(t(dissimilar.pat.frame))
这给出了
patid.68.49 patid.9
gender 1.00000 2.00000
age 41.85000 41.79000
sysbp_min 72.00000 106.00000
sysbp_max 95.00000 217.00000
diasbp_min 42.00000 53.00000
diasbp_max 61.00000 107.00000
meanbp_min 52.00000 67.00000
meanbp_max 72.00000 132.00000
resprate_min 20.00000 14.00000
resprate_max 35.00000 19.00000
tempc_min 36.00000 35.50000
tempc_max 37.55555 37.88889
spo2_min 90.00000 95.00000
spo2_max 100.00000 100.00000
bicarbonate_min 22.00000 26.00000
bicarbonate_max 22.00000 30.00000
creatinine_min 2.50000 1.20000
creatinine_max 2.50000 1.40000
glucose_min 82.00000 129.00000
glucose_max 82.00000 178.00000
hematocrit_min 28.10000 37.40000
hematocrit_max 28.10000 45.20000
potassium_min 5.50000 2.80000
potassium_max 5.50000 3.00000
sodium_min 138.00000 136.00000
sodium_max 138.00000 140.00000
bun_min 28.00000 16.00000
bun_max 28.00000 17.00000
wbc_min 2.50000 7.50000
wbc_max 2.50000 13.70000
mingcs 15.00000 15.00000
gcsmotor 6.00000 5.00000
gcsverbal 5.00000 0.00000
gcseyes 4.00000 1.00000
endotrachflag 0.00000 1.00000
urineoutput 1674.00000 887.00000
vasopressor 0.00000 0.00000
vent 0.00000 1.00000
los_hospital 19.09310 4.88130
los_icu 3.53680 5.32310
sofa 3.00000 5.00000
saps 17.00000 18.00000
posthospmort30day 1.00000 0.00000
通常我不会添加第二个答案,但这可能是这里最好的解决方案。不要担心投票。
这是与我的第一个答案相同的算法,应用于 iris 数据集。每行包含来自三种不同品种的鸢尾植物的花朵的四个空间测量值。
下面是虹膜分析,写成嵌套循环,因此您可以看到等效性。但不建议将其用于大型数据集的生产。
请熟悉起始数据和所有中间数据帧:
- 输入
iris
数据
psm_scaled
(空间测量值,缩放为均值=0,SD=1)
cs
(成对相似度矩阵)
cs.melt
(长格式的成对相似度)
最后,我汇总了一个品种与另一个品种之间所有比较的平均相似度。你会看到,同一品种个体之间的比较具有接近 1 的平均相似度,而同一品种个体之间的比较具有接近 negative1.
library(lsa)
library(reshape2)
temp <- iris[, 1:4]
iris.names <- paste0(iris$Species, '.', rownames(iris))
psm_scaled <- scale(temp)
rownames(psm_scaled) <- iris.names
cs <- lsa::cosine(t(psm_scaled))
# this is super inefficient, because cs contains
# two identical triangular matrices
cs.melt <- melt(cs)
cs.melt <- as.data.frame(cs.melt)
names(cs.melt) <- c("enc.A", "enc.B", "similarity")
names(cs.melt) <- c("flower.A", "flower.B", "similarity")
class.A <-
strsplit(as.character(cs.melt$flower.A), '.', fixed = TRUE)
cs.melt$class.A <- sapply(class.A, function(one.split) {
return(one.split[1])
})
class.B <-
strsplit(as.character(cs.melt$flower.B), '.', fixed = TRUE)
cs.melt$class.B <- sapply(class.B, function(one.split) {
return(one.split[1])
})
cs.melt$comparison <-
paste0(cs.melt$class.A , '_vs_', cs.melt$class.B)
cs.agg <-
aggregate(cs.melt$similarity, by = list(cs.melt$comparison), mean)
print(cs.agg[order(cs.agg$x),])
这给出了
# Group.1 x
# 3 setosa_vs_virginica -0.7945321
# 7 virginica_vs_setosa -0.7945321
# 2 setosa_vs_versicolor -0.4868352
# 4 versicolor_vs_setosa -0.4868352
# 6 versicolor_vs_virginica 0.3774612
# 8 virginica_vs_versicolor 0.3774612
# 5 versicolor_vs_versicolor 0.4134413
# 9 virginica_vs_virginica 0.7622797
# 1 setosa_vs_setosa 0.8698189
如果您仍然不习惯在缩放的数值数据帧上执行 lsa::cosine()
,我们当然可以进行显式成对计算。
您为 PSM 或患者的余弦相似度给出的公式在 Wikipedia
中以两种格式表示
记住向量 A 和 B 表示 PatientA 的有序属性列表和PatientB,PSM 是 A 和 B 的点积,除以(的标量积[A的大小]和[B的大小])
在 R 中的简洁表达方式是
cosine.sim <- function(A, B) { A %*% B / sqrt(A %*% A * B %*% B) }
但我们可以重写它,使其看起来更像您的 post
cosine.sim <- function(A, B) { A %*% B / (sqrt(A %*% A) * sqrt(B %*% B)) }
我想你甚至可以将它(一对个体之间的相似性计算)重写为一堆嵌套循环,但是在数据量可控的情况下,请不要。 R 针对向量和矩阵的运算进行了高度优化。如果您是 R 的新手,请不要再猜测它。顺便问一下,你的数百万行发生了什么?既然你已经下降到数万,这肯定会减轻压力。
总之,假设每个个体只有两个元素。
individual.1 <- c(1, 0)
individual.2 <- c(1, 1)
因此,您可以将 individual.1 视为穿过原点 (0,0) 和 (0, 1) 之间的一条线,将 individual.2 视为穿过原点和 (1, 1) 之间的一条线.
some.data <- rbind.data.frame(individual.1, individual.2)
names(some.data) <- c('element.i', 'element.j')
rownames(some.data) <- c('individual.1', 'individual.2')
plot(some.data, xlim = c(-0.5, 2), ylim = c(-0.5, 2))
text(
some.data,
rownames(some.data),
xlim = c(-0.5, 2),
ylim = c(-0.5, 2),
adj = c(0, 0)
)
segments(0, 0, x1 = some.data[1, 1], y1 = some.data[1, 2])
segments(0, 0, x1 = some.data[2, 1], y1 = some.data[2, 2])
那么向量individual.1和向量individual.2的夹角是多少?您猜对了,0.785 弧度,即 45 度。
cosine.sim <- function(A, B) { A %*% B / (sqrt(A %*% A) * sqrt(B %*% B)) }
cos.sim.result <- cosine.sim(individual.1, individual.2)
angle.radians <- acos(cos.sim.result)
angle.degrees <- angle.radians * 180 / pi
print(angle.degrees)
# [,1]
# [1,] 45
现在我们可以使用我之前在两个嵌套循环中定义的cosine.sim
函数来显式计算成对相似度 在每一朵鸢尾花之间。请记住,psm_scaled
已被定义为来自 iris
数据集的缩放数值。
cs.melt <- lapply(rownames(psm_scaled), function(name.A) {
inner.loop.result <-
lapply(rownames(psm_scaled), function(name.B) {
individual.A <- psm_scaled[rownames(psm_scaled) == name.A, ]
individual.B <- psm_scaled[rownames(psm_scaled) == name.B, ]
similarity <- cosine.sim(individual.A, individual.B)
return(list(name.A, name.B, similarity))
})
inner.loop.result <-
do.call(rbind.data.frame, inner.loop.result)
names(inner.loop.result) <-
c('flower.A', 'flower.B', 'similarity')
return(inner.loop.result)
})
cs.melt <- do.call(rbind.data.frame, cs.melt)
现在我们重复上面cs.melt$class.A
、cs.melt$class.B
、cs.melt$comparison
的计算,计算出cs.agg.from.loops
作为各类比较的平均相似度:
cs.agg.from.loops <-
aggregate(cs.agg.from.loops$similarity, by = list(cs.agg.from.loops $comparison), mean)
print(cs.agg.from.loops[order(cs.agg.from.loops$x),])
# Group.1 x
# 3 setosa_vs_virginica -0.7945321
# 7 virginica_vs_setosa -0.7945321
# 2 setosa_vs_versicolor -0.4868352
# 4 versicolor_vs_setosa -0.4868352
# 6 versicolor_vs_virginica 0.3774612
# 8 virginica_vs_versicolor 0.3774612
# 5 versicolor_vs_versicolor 0.4134413
# 9 virginica_vs_virginica 0.7622797
# 1 setosa_vs_setosa 0.8698189
我相信这与我们使用 lsa::cosine
得到的结果相同。
所以我想说的是...你为什么不使用lsa::cosine
?
也许你更应该关心
- 变量的选择,包括删除高度相关的变量
- scaling/normalizing/standardizing数据
- 大型输入数据集的性能
- 识别已知的相似点和不同点以进行质量控制
如前所述
我必须计算 R 中 48k 患者数据与一些预测变量之间的余弦相似性(患者相似性度量)。这是等式:PSM(P1,P2) = P1.P2/ ||P1|| ||P2||
其中 P1 和 P2 是对应于两个不同患者的预测向量,例如 P1 指数患者和 P2 将与指数 (P1) 进行比较,最后将计算成对患者相似性度量 PSM(P1,P2)。
这个过程将对所有 48,000 名患者进行。
我在 .csv 文件中添加了 300 名患者的示例数据集。请在此处找到示例数据集。https://1drv.ms/u/s!AhoddsPPvdj3hVTSbosv2KcPIx5a
首先要做的事:您可以在以下任一帖子中找到更严格的余弦相似度处理方法:
- Find cosine similarity between two arrays
- Creating co-occurrence matrix
现在,您显然在输入中混合了多种数据类型,至少
- 十进制
- 整数
- 分类
我怀疑某些整数值是布尔值或其他分类值。通常,如果您想将它们用作相似度计算的输入,则由您将它们转换为连续的数值向量。例如,录取类型 ELECTIVE
和 EMERGENCY
之间的 距离 是多少?它是名义变量还是顺序变量?我只会对我认为是数值因变量的列建模。
此外,您做了哪些工作来确保您的某些专栏与其他专栏不相关?只要对数据科学和生物医学术语有一点了解,这似乎很可能以下都是相关的:
diasbp_max
,diasbp_min
,meanbp_max
,meanbp_min
,sysbp_max
andsysbp_min
我建议去打印店订购 psm_pairs.pdf
的海报尺寸打印件。 :-) 你的眼睛更擅长检测变量之间有意义的(但非线性的)依赖关系。在您的相似性计算中,包括对同一基本现象的多次测量可能会过度加权该现象。不要忘记你可以推导像
diasbp_rage <- diasbp_max - diasbp_min
现在,我不是特别擅长线性代数,所以我从 lsa
文本分析包中导入一个余弦相似度函数。我很乐意看到 你 将你问题中的公式写成 R 函数。我会写它来比较一行与另一行,并使用两个嵌套的应用循环来获取所有比较。希望我们会得到相同的结果!
计算相似度后,我尝试找到两个最不相似的遭遇。
由于您处理的行数相对较大,因此您需要比较各种算法方法以提高效率。此外,您可以在具有多核和 lots RAM 的单台计算机上使用 SparkR/some other Hadoop solution on a cluster, or the parallel 程序包。我不知道我提供的解决方案是否是线程安全的。
想想看,对于一组 100 万名患者的遭遇,单独的换位(正如我实现的那样)可能在计算上是昂贵的。总的来说,(如果我没记错的话)随着输入中行数的增加,性能可能会呈指数下降。
library(lsa)
library(reshape2)
psm_sample <- read.csv("psm_sample.csv")
row.names(psm_sample) <-
make.names(paste0("patid.", as.character(psm_sample$subject_id)), unique = TRUE)
temp <- sapply(psm_sample, class)
temp <- cbind.data.frame(names(temp), as.character(temp))
names(temp) <- c("variable", "possible.type")
numeric.cols <- (temp$possible.type %in% c("factor", "integer") &
(!(grepl(
pattern = "_id$", x = temp$variable
))) &
(!(
grepl(pattern = "_code$", x = temp$variable)
)) &
(!(
grepl(pattern = "_type$", x = temp$variable)
))) | temp$possible.type == "numeric"
psm_numerics <- psm_sample[, numeric.cols]
row.names(psm_numerics) <- row.names(psm_sample)
psm_numerics$gender <- as.integer(psm_numerics$gender)
psm_scaled <- scale(psm_numerics)
pair.these.up <- psm_scaled
# checking for independence of variables
# if the following PDF pair plot is too big for your computer to open,
# try pair-plotting some random subset of columns
# keep.frac <- 0.5
# keep.flag <- runif(ncol(psm_scaled)) < keep.frac
# pair.these.up <- psm_scaled[, keep.flag]
# pdf device sizes are in inches
dev <-
pdf(
file = "psm_pairs.pdf",
width = 50,
height = 50,
paper = "special"
)
pairs(pair.these.up)
dev.off()
#transpose the dataframe to get the
#similarity between patients
cs <- lsa::cosine(t(psm_scaled))
# this is super inefficnet, because cs contains
# two identical triangular matrices
cs.melt <- melt(cs)
cs.melt <- as.data.frame(cs.melt)
names(cs.melt) <- c("enc.A", "enc.B", "similarity")
extract.pat <- function(enc.col) {
my.patients <-
sapply(enc.col, function(one.pat) {
temp <- (strsplit(as.character(one.pat), ".", fixed = TRUE))
return(temp[[1]][[2]])
})
return(my.patients)
}
cs.melt$pat.A <- extract.pat(cs.melt$enc.A)
cs.melt$pat.B <- extract.pat(cs.melt$enc.B)
same.pat <- cs.melt[cs.melt$pat.A == cs.melt$pat.B ,]
different.pat <- cs.melt[cs.melt$pat.A != cs.melt$pat.B ,]
most.dissimilar <-
different.pat[which.min(different.pat$similarity),]
dissimilar.pat.frame <- rbind(psm_numerics[rownames(psm_numerics) ==
as.character(most.dissimilar$enc.A) ,],
psm_numerics[rownames(psm_numerics) ==
as.character(most.dissimilar$enc.B) ,])
print(t(dissimilar.pat.frame))
这给出了
patid.68.49 patid.9
gender 1.00000 2.00000
age 41.85000 41.79000
sysbp_min 72.00000 106.00000
sysbp_max 95.00000 217.00000
diasbp_min 42.00000 53.00000
diasbp_max 61.00000 107.00000
meanbp_min 52.00000 67.00000
meanbp_max 72.00000 132.00000
resprate_min 20.00000 14.00000
resprate_max 35.00000 19.00000
tempc_min 36.00000 35.50000
tempc_max 37.55555 37.88889
spo2_min 90.00000 95.00000
spo2_max 100.00000 100.00000
bicarbonate_min 22.00000 26.00000
bicarbonate_max 22.00000 30.00000
creatinine_min 2.50000 1.20000
creatinine_max 2.50000 1.40000
glucose_min 82.00000 129.00000
glucose_max 82.00000 178.00000
hematocrit_min 28.10000 37.40000
hematocrit_max 28.10000 45.20000
potassium_min 5.50000 2.80000
potassium_max 5.50000 3.00000
sodium_min 138.00000 136.00000
sodium_max 138.00000 140.00000
bun_min 28.00000 16.00000
bun_max 28.00000 17.00000
wbc_min 2.50000 7.50000
wbc_max 2.50000 13.70000
mingcs 15.00000 15.00000
gcsmotor 6.00000 5.00000
gcsverbal 5.00000 0.00000
gcseyes 4.00000 1.00000
endotrachflag 0.00000 1.00000
urineoutput 1674.00000 887.00000
vasopressor 0.00000 0.00000
vent 0.00000 1.00000
los_hospital 19.09310 4.88130
los_icu 3.53680 5.32310
sofa 3.00000 5.00000
saps 17.00000 18.00000
posthospmort30day 1.00000 0.00000
通常我不会添加第二个答案,但这可能是这里最好的解决方案。不要担心投票。
这是与我的第一个答案相同的算法,应用于 iris 数据集。每行包含来自三种不同品种的鸢尾植物的花朵的四个空间测量值。
下面是虹膜分析,写成嵌套循环,因此您可以看到等效性。但不建议将其用于大型数据集的生产。
请熟悉起始数据和所有中间数据帧:
- 输入
iris
数据 psm_scaled
(空间测量值,缩放为均值=0,SD=1)cs
(成对相似度矩阵)cs.melt
(长格式的成对相似度)
最后,我汇总了一个品种与另一个品种之间所有比较的平均相似度。你会看到,同一品种个体之间的比较具有接近 1 的平均相似度,而同一品种个体之间的比较具有接近 negative1.
library(lsa)
library(reshape2)
temp <- iris[, 1:4]
iris.names <- paste0(iris$Species, '.', rownames(iris))
psm_scaled <- scale(temp)
rownames(psm_scaled) <- iris.names
cs <- lsa::cosine(t(psm_scaled))
# this is super inefficient, because cs contains
# two identical triangular matrices
cs.melt <- melt(cs)
cs.melt <- as.data.frame(cs.melt)
names(cs.melt) <- c("enc.A", "enc.B", "similarity")
names(cs.melt) <- c("flower.A", "flower.B", "similarity")
class.A <-
strsplit(as.character(cs.melt$flower.A), '.', fixed = TRUE)
cs.melt$class.A <- sapply(class.A, function(one.split) {
return(one.split[1])
})
class.B <-
strsplit(as.character(cs.melt$flower.B), '.', fixed = TRUE)
cs.melt$class.B <- sapply(class.B, function(one.split) {
return(one.split[1])
})
cs.melt$comparison <-
paste0(cs.melt$class.A , '_vs_', cs.melt$class.B)
cs.agg <-
aggregate(cs.melt$similarity, by = list(cs.melt$comparison), mean)
print(cs.agg[order(cs.agg$x),])
这给出了
# Group.1 x
# 3 setosa_vs_virginica -0.7945321
# 7 virginica_vs_setosa -0.7945321
# 2 setosa_vs_versicolor -0.4868352
# 4 versicolor_vs_setosa -0.4868352
# 6 versicolor_vs_virginica 0.3774612
# 8 virginica_vs_versicolor 0.3774612
# 5 versicolor_vs_versicolor 0.4134413
# 9 virginica_vs_virginica 0.7622797
# 1 setosa_vs_setosa 0.8698189
如果您仍然不习惯在缩放的数值数据帧上执行 lsa::cosine()
,我们当然可以进行显式成对计算。
您为 PSM 或患者的余弦相似度给出的公式在 Wikipedia
中以两种格式表示记住向量 A 和 B 表示 PatientA 的有序属性列表和PatientB,PSM 是 A 和 B 的点积,除以(的标量积[A的大小]和[B的大小])
在 R 中的简洁表达方式是
cosine.sim <- function(A, B) { A %*% B / sqrt(A %*% A * B %*% B) }
但我们可以重写它,使其看起来更像您的 post
cosine.sim <- function(A, B) { A %*% B / (sqrt(A %*% A) * sqrt(B %*% B)) }
我想你甚至可以将它(一对个体之间的相似性计算)重写为一堆嵌套循环,但是在数据量可控的情况下,请不要。 R 针对向量和矩阵的运算进行了高度优化。如果您是 R 的新手,请不要再猜测它。顺便问一下,你的数百万行发生了什么?既然你已经下降到数万,这肯定会减轻压力。
总之,假设每个个体只有两个元素。
individual.1 <- c(1, 0)
individual.2 <- c(1, 1)
因此,您可以将 individual.1 视为穿过原点 (0,0) 和 (0, 1) 之间的一条线,将 individual.2 视为穿过原点和 (1, 1) 之间的一条线.
some.data <- rbind.data.frame(individual.1, individual.2)
names(some.data) <- c('element.i', 'element.j')
rownames(some.data) <- c('individual.1', 'individual.2')
plot(some.data, xlim = c(-0.5, 2), ylim = c(-0.5, 2))
text(
some.data,
rownames(some.data),
xlim = c(-0.5, 2),
ylim = c(-0.5, 2),
adj = c(0, 0)
)
segments(0, 0, x1 = some.data[1, 1], y1 = some.data[1, 2])
segments(0, 0, x1 = some.data[2, 1], y1 = some.data[2, 2])
那么向量individual.1和向量individual.2的夹角是多少?您猜对了,0.785 弧度,即 45 度。
cosine.sim <- function(A, B) { A %*% B / (sqrt(A %*% A) * sqrt(B %*% B)) }
cos.sim.result <- cosine.sim(individual.1, individual.2)
angle.radians <- acos(cos.sim.result)
angle.degrees <- angle.radians * 180 / pi
print(angle.degrees)
# [,1]
# [1,] 45
现在我们可以使用我之前在两个嵌套循环中定义的cosine.sim
函数来显式计算成对相似度 在每一朵鸢尾花之间。请记住,psm_scaled
已被定义为来自 iris
数据集的缩放数值。
cs.melt <- lapply(rownames(psm_scaled), function(name.A) {
inner.loop.result <-
lapply(rownames(psm_scaled), function(name.B) {
individual.A <- psm_scaled[rownames(psm_scaled) == name.A, ]
individual.B <- psm_scaled[rownames(psm_scaled) == name.B, ]
similarity <- cosine.sim(individual.A, individual.B)
return(list(name.A, name.B, similarity))
})
inner.loop.result <-
do.call(rbind.data.frame, inner.loop.result)
names(inner.loop.result) <-
c('flower.A', 'flower.B', 'similarity')
return(inner.loop.result)
})
cs.melt <- do.call(rbind.data.frame, cs.melt)
现在我们重复上面cs.melt$class.A
、cs.melt$class.B
、cs.melt$comparison
的计算,计算出cs.agg.from.loops
作为各类比较的平均相似度:
cs.agg.from.loops <-
aggregate(cs.agg.from.loops$similarity, by = list(cs.agg.from.loops $comparison), mean)
print(cs.agg.from.loops[order(cs.agg.from.loops$x),])
# Group.1 x
# 3 setosa_vs_virginica -0.7945321
# 7 virginica_vs_setosa -0.7945321
# 2 setosa_vs_versicolor -0.4868352
# 4 versicolor_vs_setosa -0.4868352
# 6 versicolor_vs_virginica 0.3774612
# 8 virginica_vs_versicolor 0.3774612
# 5 versicolor_vs_versicolor 0.4134413
# 9 virginica_vs_virginica 0.7622797
# 1 setosa_vs_setosa 0.8698189
我相信这与我们使用 lsa::cosine
得到的结果相同。
所以我想说的是...你为什么不使用lsa::cosine
?
也许你更应该关心
- 变量的选择,包括删除高度相关的变量
- scaling/normalizing/standardizing数据
- 大型输入数据集的性能
- 识别已知的相似点和不同点以进行质量控制
如前所述