【问题标题】:Evenly distributing duplicated strings among several lists using R使用 R 在多个列表中均匀分布重复的字符串
【发布时间】:2012-12-12 09:03:07
【问题描述】:

假设我有一个长度为 150000 的字符向量。向量中的字符串不是唯一的,实际上它们是正态分布的,最常见的字符串出现 28 次,另外 24 次,超过 1000 次出现超过5次。我想将向量分成 28 个较小的向量,将字符串分布在较小的向量中,这样每个较小的向量中没有字符串出现超过两次,理想情况下只有一次(或不存在)。我需要保留每个字符串,所以我不能只做!duplicated() 理想情况下,向量的大小应该差不多。

我该怎么做呢?

我正在考虑像开始添加到第一个向量直到遇到第一个非唯一字符串,跳过它,继续填充跳过非唯一字符串直到达到 150000/28 = 5357,然后继续其他向量以相同的方式从父向量中删除字符串,一旦它们被分配给一个较小的向量?这有什么问题吗?没有令人讨厌的 for 循环森林的有效方法?

【问题讨论】:

  • 已编辑以阐明矢量应该大致相同。

标签: string r distribution


【解决方案1】:

这似乎是一个非常有趣的问题,尽管它可能只是因为我误解了它才显得有趣——我在这里得到的解决方案创建length of character vector / frequency of most frequent item 子向量,然后将每个字符串放入这些子向量的f ,其中f 是该字符串的频率。这可能比您实际要求的要复杂。

library(plyr)
# I created a file with 10000 random strings and a roughly similar frequency 
# distribution using python, and now I can't remember exactly what I did
strings <- read.csv("random_strings.txt", header=FALSE,
                    stringsAsFactors=FALSE)$V1
freq_table <- table(strings)

num_sub_vectors <- max(freq_table)
# Create a list of empty character vectors
split_list <- alply(1:num_sub_vectors, 1, function(x) return(character(0)))
for (s in names(freq_table)) {
  # Put each string into f of the sub-vectors, where f is the string's 
  # frequency
  freq <- freq_table[[s]]
  # Choose f random indexes to put this string into
  sub_vecs <- sample(1:num_sub_vectors, freq)
  for (sub in sub_vecs) {
    split_list[[sub]] <- c(split_list[[sub]], s)
  }
}

要测试它是否有效,请选择一个字符串s 或频率f,并检查s 是否出现在子向量的f 中。重复直到你有信心为止。

> head(freq_table[freq_table==15])
strings
ad ak bj cg cl cy 
15 15 15 15 15 15 
> sum(sapply(split_list, function(x) "ad" %in% x))
[1] 15

【讨论】:

  • 我想的有点复杂。我只是想在分区中大致均匀地拆分字符串,而不会在任何一个子向量中重复字符串,因此子向量的长度之和应该等于原始长度,理想情况下它们应该是相同的大小, 有一点余数。
  • 我认为这个解决方案符合大多数这些要求,除了它们的大小都相同——我的答案是大多数子向量的长度大致相同,但不完全相同。
  • 我还认为要完全满足您的要求可能比您想象的要棘手 - 任何单个向量的最大长度是 u 原始向量中唯一元素的数量,但如果有任何一个您的字符串的频率为 1,然后其余向量现在具有最大长度 u - 1,并且当您用完低频字符串时,最大值会不断减小,因此您最终会得到较短的子向量 - 我可以目前真的没有办法解决这个问题。
  • 所以上述解决方案似乎将整个集合中字符串的频率加倍。例如。在原始向量中出现 4 次的字符串将被放置在 8 个子向量中,在原始向量中出现一次的字符串将出现在两个子向量中,等等,我没有立即看到应该发生什么。你打算发生这种情况吗?最好的解决方案不会增加所有向量中字符串的总数。
  • 嗯,我以为这就是我用sum(sapply(split_list, function(x) "ad" %in% x)) 测试的内容——你是如何测试的?另一种选择是sum(sapply(split_list, function(x) length(x[x == "ad"]))),但这对我来说似乎也很好。
【解决方案2】:

这可以相当简洁地满足您的要求(每个字符串每个子向量只有一次),只需计算每个字符串出现的频率,然后根据“出现 i 次或更多次的字符串”进行分区:

inputs <- c("foo", "bar", "baz", "bar", "baz", "bar", "bar")
histo <- table(inputs)
lapply(1:max(histo), function(i) { names(histo)[histo>=i] } 

这当然会产生大小差异很大的分区,但您并不太清楚您在该区域的要求是什么。

【讨论】:

  • (1) 我想用户正在寻找等长的向量。 (2) 对象results 没有用。 (3)你的例子没有反映问题的条件,即原始向量的长度是最频繁字符串的最大出现次数的倍数。
  • 感谢您的回答。我没有指定向量的长度,因为它不是那么重要,但我试图让它们的大小大致相等。
猜你喜欢
  • 2013-04-14
  • 1970-01-01
  • 2016-06-16
  • 2013-01-11
  • 2011-11-30
  • 2021-12-16
  • 2014-10-24
  • 1970-01-01
相关资源
最近更新 更多