5

我正在寻找一种方法来删除 R 中字符串中某些位置的字符。例如,如果我们有一个 string "1,2,1,1,2,1,1,1,1,2,1,1",我想删除第三、第四、第七和第八个位置。该操作将使字符串:"1,1,2,1,1,1,1,2,1,1"

不幸的是,使用 strsplit 将字符串分解为列表不是一种选择,因为我正在使用的字符串长度超过 100 万个字符。考虑到我有大约 2,500 个字符串,这需要相当长的时间。

或者,找到一种用空字符串替换字符的方法""可以达到同样的目的——我认为。考虑到这一思路,我发现了这篇 StackOverflow 帖子:

R:我该如何替换字符串中的第 5 个元素?

不幸的是,建议的解决方案很难有效地概括,对于要删除的 2000 个位置的列表,每个输入字符串大约需要 60 秒:

subchar2 = function(inputstring, pos){
string = ""
memory = 0
for(num in pos){
    string = paste(string, substr(inputstring, (memory+1), (num-1)), sep = "")
    memory = num
}
string = paste(string, substr(inputstring,(memory+1), nchar(inputstring)),sep = "")
return(string)
}

调查这个问题,我发现了一段代码,它似乎将某些位置的字符替换为"-"

subchar <- function(string, pos) {
        for(i in pos) {
            string <- gsub(paste("^(.{", i-1, "}).", sep=""), "\\1-", string)
        }
        return(string)
}

我不太了解正则表达式(还),但我强烈怀疑这些方面的某些东西在时间上比第一个代码解决方案要好得多。不幸的是,当 pos 中的值变高时,这个 subchar 函数似乎会中断:

> test = subchar(data[1], 257)
Error in gsub(paste("^(.{", i - 1, "}).", sep = ""), "\\1-", string) :
invalid regular expression '^(.{256}).', reason 'Invalid contents of {}'

我也在考虑尝试使用 SQL 将字符串数据读入表中,但我希望会有一个优雅的字符串解决方案。在 R 中执行此操作的 SQL 实现似乎相当复杂。

有任何想法吗?谢谢!

4

3 回答 3

3

strsplit如果您使用fixed = TRUE. 粗略推断,处理 2,500 个由 1,000,000 个逗号分隔的整数组成的字符串需要 2 分钟多一点的时间。

N <- 1000000
x <- sample(0:1, N, replace = TRUE)
s <- paste(x, collapse = ",")

# this is a vector of 10 strings
M <- 10
S <- rep(s, M)

system.time(y <- strsplit(S, split = ","))
# user  system elapsed 
# 6.57    0.00    6.56 
system.time(y <- strsplit(S, split = ",", fixed = TRUE))
# user  system elapsed 
# 0.46    0.03    0.50

这几乎比使用扫描快 3 倍:

system.time(scan(textConnection(S), sep=",", what="a"))
# Read 10000000 items
# user  system elapsed 
# 1.21    0.09    1.42
于 2012-08-21T01:39:16.467 回答
3

在使用中阅读它们scan()。您可以将分隔符设置为 "," 和 what="a"。您可以scan一次使用一条“线”,nlines=1如果它是textConnection,则“管道”将“记住”上次阅读时的位置。

x <- paste( sample(0:1, 1000, rep=T), sep=",")
xin <- textConnection(x)

x995 <- scan(xin, sep=",", what="a", nmax=995)
# Read 995 items
x5 <- scan(xin, sep=",", what="a", nmax=995)
# Read 5 items

这是一个带有 5 条“线”的插图

> x <- paste( rep( paste(sample(0:1, 50, rep=T), collapse=","),  5),  collapse="\n")
> str(x)
 chr "1,0,0,0,0,1,0,0,1,1,1,0,1,1,0,0,0,1,1,1,1,0,0,1,0,1,0,1,0,0,1,0,0,0,1,0,1,0,0,1,1,1,1,1,0,0,0,1,0,0\n1,0,0,0,0,1,0,0,1,1,1,0,1,"| __truncated__
> xin <- textConnection(x)
> x1 <- scan(xin, sep=",", what="a", nlines=1)
Read 50 items
> x2 <- scan(xin, sep=",", what="a", nlines=1)
Read 50 items
> x3 <- scan(xin, sep=",", what="a", nlines=1)
Read 50 items
> x4 <- scan(xin, sep=",", what="a", nlines=1)
Read 50 items
> x5 <- scan(xin, sep=",", what="a", nlines=1)
Read 50 items
> x6 <- scan(xin, sep=",", what="a", nlines=1)
Read 0 items
> length(x1)
[1] 50
> length(x1[-c(3,4,7,8)])
[1] 46
> paste(x1, collapse=",")
[1] "1,0,0,0,0,1,0,0,1,1,1,0,1,1,0,0,0,1,1,1,1,0,0,1,0,1,0,1,0,0,1,0,0,0,1,0,1,0,0,1,1,1,1,1,0,0,0,1,0,0"
> 
于 2012-08-21T01:23:05.167 回答
2

一种快速修复方法是删除 for 循环中的粘贴

subchar3<-function(inputstring, pos){
string = ""
memory = 0
for(num in pos){
    string = c(string,substr(inputstring, (memory+1), (num-1)))
    memory = num
}
string = paste(c(string, substr(inputstring,(memory+1), nchar(inputstring))),collapse = "")
return(string)
}
data<-paste(sample(letters,100000,replace=T),collapse='')
remove<-sample(1:nchar(data),200)
remove<-remove[order(remove)]
s2<-subchar2(data,remove)
s3<-subchar3(data,remove)
identical(s2,s3)
#[1] TRUE

> library(rbenchmark)
> benchmark(subchar2(data,remove),subchar3(data,remove),replications=10)
                    test replications elapsed relative user.self sys.self
1 subchar2(data, remove)           10   43.64 40.78505     39.97      1.9
2 subchar3(data, remove)           10    1.07  1.00000      1.01      0.0
  user.child sys.child
1         NA        NA
2         NA        NA
于 2012-08-21T01:15:06.823 回答