【问题标题】:Create balanced subsets based on similarity of multiple columns根据多列的相似性创建平衡子集
【发布时间】:2017-07-27 23:48:13
【问题描述】:

我正在寻找找到行子集的可能性(一个子集应包含 6 行),其中多列的值均值最相似。所以,我希望 R 搜索我的 data.frame 并创建每个 6 行的子集,以便最终这些子集彼此最相似。相似度可以用欧几里得距离来衡量(正如@David Robinson 所指出的那样)。

我的数据是这样的:

  TID   Cue1  Cue2  Cue3
  1    2.06   1.90  3.82
  2    5.18   4.13  5.10
  3    5.09   2.85  2.80
  4    1.93   4.14  4.75
  ...   ...    ...   ...       

我现在想知道 R 中是否有一种方法,我发现以下内容:

-给我例如4 个子集,每个子​​集包含 6 行,其中 4 个子集在 Cue1、Cue2 和 Cue3 均值(SD 不重要)中最可能相似,而 每个子集包含唯一的行(子集之间没有重复的行)

一个例子是(与我的例子中的数据不匹配):

-子集 1 包含 TID 1、TID 6、TID 14、TID 28、TID 39、TID 50,并且该子集具有提示均值(Cue1 = 3,2;Cue2 = 2, 5; 提示 3 = 4)

-子集 2 包含 TID 3、TID 12、TID 20、TID 40、TID 54、TID 59,并且该子集具有提示均值(Cue1 = 3,3;Cue2 = 2, 6;Cue3 = 4,1)。

因此这两个子集在提示手段上非常(最)相似。 R 现在应该将构成子集的行号(或 TID 值)命名为我。

在 R 中是否有可能做到这一点?

以下是我的数据外观的可重现示例:

    mysamp <- function(n, m, s, lwr, upr, nnorm) {
  set.seed(1)
  samp <- rnorm(nnorm, m, s)
  samp <- samp[samp >= lwr & samp <= upr]
  if (length(samp) >= n) {
    return(sample(samp, n))
  }  
 } 
Cue1 <- mysamp(n=60, m=3, s=1.5, lwr=1, upr=6, nnorm=1000)
Cue2 <- mysamp(n=60, m=3, s=2.5, lwr=1, upr=6, nnorm=1000)
Cue3 <- mysamp(n=60, m=4, s=1.5, lwr=1, upr=6, nnorm=1000)

df <- data.frame(TID= 1:60, Cue1= Cue1, Cue2= Cue2, Cue3= Cue3)

【问题讨论】:

  • 1.应该使用什么指标来量化行之间的相似性?例如,试图最小化成对(1-2、1-3、1-4、2-3 等)欧几里得距离(平方和的平方)是否合理? 2. 子集可以重叠吗? 3. 您需要一个可证明的全局最优解决方案,还是需要一个“相当不错”的解决方案?
  • 例如下面的聚类方式:distances &lt;- dist(df[, -1]); h &lt;- hclust(distances); plot(h);让您非常接近找到相似行的组。您需要更多的算法工作来提取特定大小的组
  • 感谢您的第一个想法!我仍然很难将它应用于我的问题,因为每个子集有 6 个案例的特定大小。您知道如何提取特定大小的组吗?由于我需要使用更大的数据框来执行此操作,因此我希望找到一种自动计算子集的方法。我需要找到每个 6 行的 12 个子集,其中一行只能用于一个子集。我不需要最佳解决方案,一个很好的解决方案就可以完美地工作!而且欧几里得距离是完全合理的,是的!

标签: r subset cluster-analysis similarity balance


【解决方案1】:

这是一个聚类问题,因此您可以通过以下方式解决它:

  • 计算距离矩阵
  • 使用它来构建相似节点组的“树”
  • 提取在树上显示为最低的您大小的子集群

距离矩阵和层次聚类可以如下:

distances <- dist(df[, -1])
h <- hclust(distances)

有很多方法可以通过算法从树上拉出低簇;因为我习惯于使用 dplyr/purrr/tidyr,所以我将展示一种解决方案。这采用了使用cutree 将树在每个可能的级别上拆分的方法,然后找到每组六个第一次出现的时间。

library(dplyr)
library(tidyr)
library(purrr)

clusterings <- data_frame(ncluster = seq(nrow(df), 1)) %>%
  unnest(membership = map(ncluster, ~ cutree(h, .))) %>%
  group_by(ncluster) %>%
  mutate(row = row_number()) %>%
  ungroup() %>%
  nest(-ncluster, -membership) %>%
  mutate(size = map_dbl(data, nrow)) %>%
  filter(size == 6) %>%
  distinct(membership, .keep_all = TRUE) %>%
  unnest(data) %>%
  mutate(TID = df$TID[row])

根据您的数据,返回:

# A tibble: 42 × 5
   ncluster membership  size   row   TID
      <int>      <int> <dbl> <int> <int>
1        29          9     6     9     9
2        29          9     6    30    30
3        29          9     6    39    39
4        29          9     6    41    41
5        29          9     6    43    43
6        29          9     6    57    57
7        21         13     6    15    15
8        21         13     6    20    20
9        21         13     6    25    25
10       21         13     6    29    29
# ... with 32 more rows

因此,(9, 30, 39, 41, 43, 57) 构成您的第一组 6,而第二组以 (15, 20, 25, 29...) 开始

【讨论】:

  • 感谢您的回复!不幸的是,对于data.frame“df”和我的实际错误,我收到以下错误: rank(x,ties.method = “first”,na.last = “keep”)错误:缺少参数“x”,没有默认值。恐怕我无法完全理解您使用该功能逐步执行的操作。因此,我真的不知道如何解决该错误。你有什么想法吗?
  • 很抱歉再次打扰您,但是您对解决代码中的“rank( )”错误有什么想法吗?非常感谢您的帮助!
猜你喜欢
  • 2018-07-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-21
  • 1970-01-01
  • 2021-11-24
相关资源
最近更新 更多