R 一条记录和整个数据帧之间的最小不相似性
我试图使计算大规模数据集(600000条记录)记录中的不相似性成为可能 第一项任务是使用单个记录和整个数据之间的欧氏距离计算相异性。frame排除该记录 考虑到以下示例:R 一条记录和整个数据帧之间的最小不相似性,r,similarity,R,Similarity,我试图使计算大规模数据集(600000条记录)记录中的不相似性成为可能 第一项任务是使用单个记录和整个数据之间的欧氏距离计算相异性。frame排除该记录 考虑到以下示例: mydf <- data.frame(var1 = rnorm(5), var2 = rnorm(5), var3 = rnorm(5)) one_row <- mydf[1,] 正确答案 Jesse Tweedle和won782的答案对我的问题都是正确的 Jesse Tweedle的积极方面是可以定制距离函数,
mydf <- data.frame(var1 = rnorm(5), var2 = rnorm(5), var3 = rnorm(5))
one_row <- mydf[1,]
正确答案
Jesse Tweedle和won782的答案对我的问题都是正确的
Jesse Tweedle的积极方面是可以定制距离函数,允许使用混合数据类型。消极的一面是,它不是一个单一的表达式,而是一个函数管道
won782的优点在于它是在一个表达式中执行的。消极的方面是,它只适用于矩阵,因此是数值变量
我选择won782回答,因为他的解决方案可以很容易地扩展为计算轮廓标准的基本组件,而无需存储相异矩阵 如果我正确理解了您的问题,您希望对给定向量执行行操作,并计算每行的欧几里德距离
mydf <- data.frame(var1 = rnorm(5), var2 = rnorm(5), var3 = rnorm(5))
one_row <- mydf[1,]
result = apply(mydf, 1, function(x) {
sqrt(sum((x - one_row)^2))
})
result
[1] 0.000000 3.333031 3.737814 1.875482 4.216042
在较大数据集上对两种方法进行基准测试
> mydf <- data.frame(var1 = rnorm(10000), var2 = rnorm(10000), var3 = rnorm(10000))
> one_row <- mydf[1,]
> # Matrix operation method
> system.time({
+ sqrt(rowSums((t(t(as.matrix(mydf)) - as.numeric(one_row)))^2))
+ })
user system elapsed
0.000 0.000 0.001
> # Apply Method
> system.time({
+ apply(mydf, 1, function(x) {
+ sqrt(sum((x - one_row)^2))
+ })
+ })
user system elapsed
5.186 0.014 5.204
>mydf一行矩阵运算法
>系统时间({
+sqrt(行和((t(作为矩阵(mydf))-作为数字(一行))^2))
+ })
用户系统运行时间
0.000 0.000 0.001
>#应用方法
>系统时间({
+应用(mydf,1,函数(x){
+sqrt(总和((x-一行)^2))
+ })
+ })
用户系统运行时间
5.186 0.014 5.204
显然,矩阵运算是一种更快的方法。问题:
您可以在mydf
上使用dist
,但答案对于您的计算机来说太大(1e11
-ish元素)。因此,挑战在于计算整个数据集每行x的欧几里德距离。你不想一次又一次地重复整个过程,因为你要重复60万次。但是您可以编写一个矢量化函数来计算欧几里德距离,并使用tidyverse
东西来简洁地应用它
答复:
编写一个函数euc
,并在第二个参数上对其进行矢量化
library(tidyverse)
euc <- function(x, y) {
sqrt(sum((x - y)^2))
}
euc_ <- Vectorize(euc, vectorize.args = "y")
calculate_distances <- function(row, df) {
dists <- euc_(row, split(df, 1:nrow(df)))
# gives you name of row and distance that gives minimum distance.
dists[dists>0 & dists == min(dists[dists>0])] %>% enframe()
}
是否可以将操作矢量化而不是应用循环?原因是,要为每一行计算最相似的行,将需要一段不可行的时间。它不应用nrow(mydf)矢量化操作,而是执行nrow(mydf)apply循环。矩阵方法肯定更快。唯一的缺点是它不能用于混合数据类型。基本上,通过这一步,我们直接获得与每条记录最近的记录,而不存储整个距离矩阵。此外,作为矢量化操作,我们可以快速计算相似度。此外,作为计算距离的函数,我们可以将其更改为欧几里得以外的度量。
> mydf <- data.frame(var1 = rnorm(10000), var2 = rnorm(10000), var3 = rnorm(10000))
> one_row <- mydf[1,]
> # Matrix operation method
> system.time({
+ sqrt(rowSums((t(t(as.matrix(mydf)) - as.numeric(one_row)))^2))
+ })
user system elapsed
0.000 0.000 0.001
> # Apply Method
> system.time({
+ apply(mydf, 1, function(x) {
+ sqrt(sum((x - one_row)^2))
+ })
+ })
user system elapsed
5.186 0.014 5.204
library(tidyverse)
euc <- function(x, y) {
sqrt(sum((x - y)^2))
}
euc_ <- Vectorize(euc, vectorize.args = "y")
calculate_distances <- function(row, df) {
dists <- euc_(row, split(df, 1:nrow(df)))
# gives you name of row and distance that gives minimum distance.
dists[dists>0 & dists == min(dists[dists>0])] %>% enframe()
}
mydf <- data.frame(var1 = rnorm(5), var2 = rnorm(5), var3 = rnorm(5))
mydf %>%
mutate(n = row_number()) %>%
group_by(n) %>%
nest(var1, var2, var3) %>%
mutate(ans = map(data, calculate_distances, df = mydf)) %>%
unnest(ans, data)
# A tibble: 5 x 6
n name value var1 var2 var3
<int> <chr> <dbl> <dbl> <dbl> <dbl>
1 1 4 1.027080 0.035684445 0.3152272 1.9001506
2 2 5 1.453509 -0.985996620 0.2650241 -0.2146157
3 3 2 1.645737 0.009665813 -0.8393461 0.4907029
4 4 1 1.027080 0.314943627 0.9910671 1.1789382
5 5 2 1.453509 0.436344415 0.5309611 -0.3521368