R语言 split()返回“较长对象长度不是较短对象长度的倍数”

bjp0bcyl  于 2022-12-06  发布在  其他
关注(0)|答案(1)|浏览(193)

上下文

我最近问过这个问题:
Comparing partitions from split() using a nested for loop containing an if statement
其中我需要使用@robertdj提供的代码修复,根据距离矩阵比较split()生成的分区

set.seed(1234) # set random seed for reproducibility

# generate random normal variates
x <- rnorm(5)
y <- rnorm(5)

df <- data.frame(x, y) # merge vectors into dataframe
d <- dist(x) # generate distance matrix

splt <- split(d, 1:5) # split data with 5 values in each partition

for (i in 1:length(splt)) {
for (j in 1:length(splt)) {
    if (i != j) {
        a <- length(which(splt[[i]] >= min(splt[[j]]))) / length(splt[[i]])
        b <- length(which(splt[[j]] <= max(splt[[i]]))) / length(splt[[j]])
        }
    }
}

我生成了一个MWE,其中每个分割包含相同数量的元素。我这样做只是为了说明的目的,完全知道这不一定适用于真实的数据。
按照罗伯特·哈肯的评论,如果我这样做的话

d <- na.omit(d[lower.tri(d)])

我得到了长度不等的分区。

真实的数据

然而,我的真实的数据没有“相同大小”的属性。我的真实数据包含的分区比我的MWE中只有5个多得多。
这是我的代码

splt <- split(dist_matrix, sub("(?:(.*)\\|){2}(\\w+)\\|(\\w+)\\|.*?$", "\\1-\\2", colnames(dist_matrix)))

距离矩阵dist_matrix包含FASTA标头,我从中提取了物种名称。
然后我在双重嵌套循环中使用上面的splt
例如,splt[[4]]包含5个值,而splt[[10]]包含9个值。

splt[[4]]
[1] 0.1316667 0.1383333 0.1166667 0.1333333 0.1216667

splt[[10]]
 [1] 0.1450000 0.1483333 0.1316667 0.1316667 0.1333333 0.1333333 0.1166667 0.1166667 0.1200000

预期输出

对于我的真实的问题,每个分区对应于单个物种到所有其他独特物种的距离,因此,如果物种X有两个DNA序列代表它,而总共有10个物种,那么物种X的分区应该包含20个距离,但是我不希望分区包含物种A的两个序列之间的距离。
splt将因此包含用于所有种类的10个分区(每个分区不必具有相同长度
ab的预期输出是0-1之间的数字,包括0和1。我认为这些数字在我的真实的示例中应该很小,但当我尝试运行代码时,它们却很大,我认为这是warning()的结果。
我所做的
我一直在读SO,%in%通常用于解决警告

In splt[[i]] == splt[[j]] :
  longer object length is not a multiple of shorter object length

除了在我的情况下,我相信我会需要%notin% <- Negate(%in%)
然而,%notin%在我的原始帖子中给出了错误

the condition has length > 1

问题

如何更改嵌套循环以删除警告?

bgibtngc

bgibtngc1#

我将通过“解释”你所说的部分内容,抛弃你的代码,看看我能想出什么来。如果没有别的,它可能会引发对话,解释我的解释中哪些是正确的(哪些是不正确的)。
从随机数据生成的splt开始,然后用更长的向量替换元素4和5,

set.seed(1234)
x <- rnorm(5)
y <- rnorm(5)
df <- data.frame(x, y)
d <- dist(x)
splt <- split(d, 1:5)
splt[[4]] <- rnorm(4)
splt[[5]] <- rnorm(10)

我们有:

splt <- list("1" = c(1.48449499149608, 2.62312694474001), "2" = c(2.29150692606848, 0.15169544670039), "3" = c(1.13863195324393, 3.43013887931241), "4" = c(-0.477192699753547, -0.998386444859704, -0.77625389463799, 0.0644588172762693), "5" = c(-0.693720246937475, -1.44820491038647, 0.574755720900728, -1.02365572296388, -0.0151383003641817, -0.935948601168394, 1.10229754620026, -0.475593078869057, -0.709440037512506, -0.501258060594761))
splt
# $`1`
# [1] 1.484495 2.623127
# $`2`
# [1] 2.2915069 0.1516954
# $`3`
# [1] 1.138632 3.430139
# $`4`
# [1] -0.47719270 -0.99838644 -0.77625389  0.06445882
# $`5`
#  [1] -0.6937202 -1.4482049  0.5747557 -1.0236557 -0.0151383 -0.9359486  1.1022975 -0.4755931 -0.7094400 -0.5012581

你引用了像which(splt[[i]] >= min(splt[[j]]))这样的表达式,我把它解释为“splt[[i]]高于splt[[j]]中最大值的比率是多少。(例如)splt[[1]]与这里的splt[[2]]splt[[5]]中的所有,并且对于其它的也是如此,我们会得到一个正方形matrix,对角线是splt[[i]]-vs-splt[[i]](可能没什么意思)。
一些快速的数学运算,让我们知道我们最终应该得到什么:

splt[[1]]
# [1] 1.484495 2.623127
range(splt[[2]])
# [1] 0.1516954 2.2915069

由于[[1]]中的1大于2的最大值2.29,我们期望0.5在两者之间进行比较(对于>= max(.));类似地,没有[[1]]低于0.15,因此我们期望在那里有0
类似地,[[5]][[4]]上:

splt[[5]]
#  [1] -0.6937202 -1.4482049  0.5747557 -1.0236557 -0.0151383 -0.9359486  1.1022975 -0.4755931 -0.7094400 -0.5012581
range(splt[[4]])
# [1] -0.99838644  0.06445882

### 2 of 10 are greater than the max
sum(splt[[5]] >= max(splt[[4]])) / length(splt[[5]])
# [1] 0.2

### 9 of 10 are lesser than the min
sum(splt[[5]] <= min(splt[[4]])) / length(splt[[5]])
# [1] 0.2

我们可以使用outer,但有时候会让人感到困惑,特别是在这种情况下,我们需要对传递给它的anon-func执行Vectorize。我将把双for循环前提修改为嵌套的sapply调用。

大于另一个的最大值

sapply(splt, function(y) sapply(setNames(splt, paste0("max", seq_along(splt))), function(z) sum(y >= max(z)) / length(y)))
#        1   2   3    4   5
# max1 0.5 0.0 0.5 0.00 0.0
# max2 0.5 0.5 0.5 0.00 0.0
# max3 0.0 0.0 0.5 0.00 0.0
# max4 1.0 1.0 1.0 0.25 0.2
# max5 1.0 0.5 1.0 0.00 0.1

判读和子集验证:

  • 1max of 2的关系:将X1 M23 N1 X(第一列)与来自X1 M24 N1 X(第二行)的最大值进行比较,X1 M25 N1 X的值的一半更大,因此我们得到0.5(如所期望的)。
  • 5max of 4的关系:将X1 M28 N1 X(第五列)与来自X1 M29 N1 X(第四行)的最大值进行比较,X1 M30 N1 X满足条件。

小于另一个的最小值

sapply(splt, function(y) sapply(setNames(splt, paste0("min", seq_along(splt))), function(z) sum(y <= min(z)) / length(y)))
#        1   2   3    4   5
# min1 0.5 0.5 0.5 1.00 1.0
# min2 0.0 0.5 0.0 1.00 0.8
# min3 0.0 0.5 0.5 1.00 1.0
# min4 0.0 0.0 0.0 0.25 0.2
# min5 0.0 0.0 0.0 0.00 0.1

相同的两对:

  • 1min of 2(第2行,第1列)是0,符合预期
  • 5min of 4(第4行,第5列)是0.2,符合预期
  • 编辑 *:@compbiostats指出,虽然sum(..)应该会产生与length(which(..))相同的结果,但后者可能对丢失数据更稳健(例如,NA值,c.f.,Difference between sum(), length(which()), and nrow() in R)。对于共享该弹性的sum(..),在上面的调用中,我们应该将na.rm=TRUE)添加到sum(.)min(.)中。

相关问题