我有一个数字向量,我想将它们分析为字符。对于每组数字(即" 3412123401234"),我想知道什么是模式,优先考虑最常出现的模式长度大于1的模式。在&#34的情况下; 3412123401234",我希望它能够认识到" 34"作为模式和出现为3。
我的算法非常低效,需要永久循环一个包含100000多个数字集的列表。需要一种更有效的方式以矢量方式处理它。
repeats = function(string){
out = c()
check.till = floor(nchar(string)/2)
for (start in 1:nchar(string)){
for (end in 1:check.till){
pat = substr(string,start,start+end)
repeats = length(gregexpr(pat,string)[[1]])
length = nchar(pat)
if (length >= 2) out = rbind(out, c(pat, repeats, length))
}
}
out = as.data.frame(out, stringsAsFactors = F)
colnames(out) = c("Pattern","Repeats","Pat.Length")
out$Repeats = as.integer(out$Repeats)
out$Pat.Length = as.integer(out$Pat.Length)
out = out[out$Repeats > 1,]
out = out[order(out[,2],out[,3],decreasing = T),]
out = out[1,]
out[is.na(out)] = 0
return(out)
}
答案 0 :(得分:0)
我不完全确定这是否是一个解决方案,但我尝试的是将矢量拆分为所有独特的组合。
我的想法是所有组合都包含在“对角矩阵”的上半部分中:
d <- c("3412123401234")
# create function
make.matrix <- function(x,y) {
vl <- nchar(d)
OUT <- seq(x,nchar(y),1)
if(length(OUT) < vl) OUT <- c(OUT,rep(NA,vl-length(OUT)))
OUT
}
mm <- sapply(1:nchar(d), make.matrix, d)
mm
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12] [,13]
tmp 1 2 3 4 5 6 7 8 9 10 11 12 13
tmp 2 3 4 5 6 7 8 9 10 11 12 13 NA
tmp 3 4 5 6 7 8 9 10 11 12 13 NA NA
tmp 4 5 6 7 8 9 10 11 12 13 NA NA NA
tmp 5 6 7 8 9 10 11 12 13 NA NA NA NA
tmp 6 7 8 9 10 11 12 13 NA NA NA NA NA
tmp 7 8 9 10 11 12 13 NA NA NA NA NA NA
tmp 8 9 10 11 12 13 NA NA NA NA NA NA NA
tmp 9 10 11 12 13 NA NA NA NA NA NA NA NA
tmp 10 11 12 13 NA NA NA NA NA NA NA NA NA
tmp 11 12 13 NA NA NA NA NA NA NA NA NA NA
tmp 12 13 NA NA NA NA NA NA NA NA NA NA NA
tmp 13 NA NA NA NA NA NA NA NA NA NA NA NA
现在我使用str_sub
包的stringr
函数根据第一行的起始值与矩阵mm
library(stringr)
mm2 <- sapply(2:nrow(mm), function(x,y) str_sub(string= y, start= mm[1,], end= mm[x,]), d)
最后计算独特的模式:
counts <- sort(table(mm2),decreasing = T)
您想要的输出:
res <- data.frame("nlength"=sapply(names(counts),nchar),"counts"=counts)
head(res)
nlength counts
12 2 3
34 2 3
123 3 2
1234 4 2
23 2 2
234 3 2
答案 1 :(得分:0)
基础R中的另一种方法(与实际算法相差不大,主要使用正则表达式来获得长度为2的可能匹配):
str<-c("3412123401234") # example entries
replength<-function(pat,s) {
length( gregexpr(pat,s)[[1]] )
}
repeats<-function(s) {
r<-sapply(
unique(
regmatches( s, gregexpr("(\\d{2,})(?=.*\\1)", s, perl=T) )[[1]]
),
replength,s=s )
pat<-names(r[r==max(r)][1])
data.frame("Pattern"=pat,"Repeats"=unname(r[r==max(r)][1]),"Pat.length"=nchar(pat),stringsAsFactors=FALSE)
}
这给出了输出:
> repeats(str)
Pattern Repeats Pat.length
1 34 3 2
在第一个示例中,它将跳过一些中间匹配123
,具体取决于它们在字符串中的显示方式。但是,如果它们不匹配,那么它们应该被另一个最长或等效的匹配“取代”(我没有找到证明它错误的测试用例)。
答案的基准(所有函数的代码都很长,所以我创建了gist:
> microbenchmark(original(str),jimbou(str),tensibai(str),times=3)
Unit: microseconds
expr min lq mean median uq max neval
original(str) 1439.982 1722.5050 1849.559 2005.028 2054.347 2103.667 3
jimbou(str) 1866.474 1994.3365 2227.586 2122.199 2408.142 2694.086 3
tensibai(str) 468.971 494.9145 558.109 520.858 602.678 684.498 3
答案 2 :(得分:-1)
正如其他人所指出的那样,2克图案总是至少与最常见的图案相关联,所以它(几乎)只需要考虑2克。*
只是为了好玩,请考虑这个python 3解决方案:
# Solution
from collections import Counter
def most_common_2gram(row):
pairs = [tuple(row[j:j+2]) for j in range(len(row)-1)]
return Counter(pairs).most_common(1) # or most_common(k) as desired
# Testing Data
from random import randint
nrow = int(1e6)
ncol = 10
x = [[randint(0,9) for j in range(ncol)] for i in range(nrow)]
# Performance Test
%timeit [most_common_2gram(row) for row in x]
# Time result: 21 seconds (from %paste into IPython)
使用20列运行示例:
x[0:5]
Output:
[[0, 8, 1, 7, 9, 7, 7, 3, 8, 5, 1, 5, 4, 7, 8, 5, 4, 2, 3, 5],
[6, 5, 4, 0, 9, 0, 0, 4, 4, 3, 7, 1, 7, 0, 7, 5, 1, 9, 0, 5],
[2, 4, 8, 5, 8, 9, 5, 9, 0, 8, 8, 2, 4, 8, 1, 6, 3, 7, 8, 1],
[5, 6, 6, 7, 1, 7, 9, 3, 3, 0, 7, 9, 5, 7, 6, 3, 8, 5, 3, 3],
[4, 6, 3, 9, 1, 5, 5, 4, 9, 0, 2, 1, 5, 3, 4, 2, 4, 1, 4, 5]]
out[0:5]
Output: [[((5, 4), 2)], [((9, 0), 2)], [((4, 8), 2)], [((3, 3), 2)], [((1, 5), 2)]]
如果您想要所有模式,而不仅仅是最常见的模式,您可以将Counter对象转换为列表并按计数排序。例如:
counts = Counter({(0,2): 2, (3,4): 3, (1,6): 1})
sorted(counts.items(),key=lambda pc: pc[1],reverse=True)
Output: [((3, 4), 3), ((0, 2), 2), ((1, 6), 1)]
*唯一可能的例外是如果2克的频率等于3克(或更多),你希望3克+是首选。可以通过更复杂的代码检测和处理这种情况。