转换循环以应用,虹膜示例

时间:2019-10-09 13:31:01

标签: r for-loop optimization apply

我有一段代码可以使用“ iris”数据集编写(尽管我的数据集要大得多)。

这个想法是要计算一个物种的所有元素之间相对于其他物种的所有元素的所有可能距离。

element1和element2的距离是使用以下几何距离计算的:

distance =(((Sepal_Width_element1-Sepal_Width_element2)^ 2 +(Petal_Length_element1-Petal_Length_element2)^ 2)^ 0.5

如果该距离小于阈值,我们将存储此值以进行进一步分析。

我能够使用for循环编写任务,但我相信其中一个“应用”功能可以加快代码的速度并使代码更具可读性。

代码如下:

threshold=20
lsp_names=unique(iris$Species) #define a vector of names for each unique species
for(n1 in 1:(length(lsp_names)-1) ){
  for(n2 in (n1+1):length(lsp_names)){

    n_spec1=lsp_names[n1] ## name of the species 1
    n_spec2=lsp_names[n2] ## name of the species 2
    ## generate a data frame for the species with name n_spec1
    gph1=iris[iris$Species==n_spec1,]
    ## generate a data frame for the species with name n_spec2
    gph2=iris[iris$Species==n_spec2,]

    dist_values=NULL
    ## loop trough all possible couples between the species n_spec1 and n_spec2,
    ## evaluate the distance and store it if it is lower than the threshold
    for(i in 1:nrow(gph1)){
      for(j in 1:nrow(gph2)){
        d=((gph1$Sepal.Width[i]-gph2$Sepal.Width[j])^2 + (gph1$Petal.Length[i]-gph2$Petal.Length[j])^2)^0.5
        if(d<=threshold){
          dist_values=c(dist_values,d)
        }
      }
    }

    ## print a summary
    a_std=sd(dist_values)
    a_mean=mean(dist_values)
    message(sprintf("distance between:%s %s mean:%f  sigma:%f\n", n_spec1, n_spec2, a_mean, a_std))
  }
}

我的输出:

distance between:setosa versicolor mean:2.923921  sigma:0.442498
distance between:setosa virginica mean:4.146551  sigma:0.557892
distance between:versicolor virginica mean:1.389100  sigma:0.703420

2 个答案:

答案 0 :(得分:2)

这个怎么样?您可以将数据集与其自身连接,然后过滤出物种相同的行,从而获得物种不同的宽数据框:

ii <- merge(iris, iris, by = NULL, all = TRUE)
ii <- ii[with(ii, as.numeric(ii$Species.x) < as.numeric(ii$Species.y)), ]

然后您可以计算元素之间的距离:

ii$dist <- sqrt((ii$Petal.Width.x - ii$Petal.Width.y)^2 + (ii$Sepal.Length.x - ii$Sepal.Length.y)^2)

最后,您可以按物种对计算平均距离:

aggregate(ii[, 'dist'], by = list(ii$Species.x, ii$Species.y), mean)
     Group.1    Group.2        x
1     setosa versicolor 1.497375
2     setosa  virginica 2.441457
3 versicolor  virginica 1.166729

不过,我没有得到您所得到的价值,我也不知道为什么。

答案 1 :(得分:1)

我已经重写了您的代码,以摆脱物种循环和个人循环中的for循环。

首先,不需要遍历个人来计算距离。因为dist()函数是矢量化的,因此可以像查找矩阵一样找到矩阵中所有行对之间的欧几里得距离。

第二,我们可以使用combn()函数列出所有物种对,然后找到每个物种对中所有个体之间的平均距离。

代码

这是代码(我没有提供您的摘要打印消息)。

# Set threshold
threshold <- 20

# Calculate Euclidean distances between all pairs of individuals
iris_dist <- dist(iris[, c('Sepal.Width', 'Petal.Length')], method = 'euclidean')

# Convert the dist object to a matrix so we can index it by 2 dimensions
iris_matrix <- as.matrix(iris_dist)

# Find all possible pairs of species in iris dataset, as a list
iris_species <- unique(iris$Species)
iris_pairs <- combn(iris_species, 2, simplify = FALSE)

# Calculate mean and standard deviation of distances of individuals of each pair of species
lapply(iris_pairs, function(species) {
  # Subset distance matrix for the pair
  dist_values <- iris_matrix[iris$Species %in% species[1], iris$Species %in% species[2]]
  # Retain only values below threshold
  dist_values <- dist_values[dist_values <= threshold]
  # Calculate mean and SD, and return
  return(c(mean = mean(dist_values), sd = sd(dist_values)))
})

输出

物种对列表(iris_pairs):

[[1]]
[1] setosa     versicolor

[[2]]
[1] setosa    virginica

[[3]]
[1] versicolor virginica 

跨物种距离的均值和标准差的列表:

[[1]]
     mean        sd 
2.9239210 0.4424981 

[[2]]
     mean        sd 
4.1465515 0.5578919 

[[3]]
     mean        sd 
1.3891000 0.7034196