识别字符串中的第一个匹配位置
Identify first match position in a string
我有一个字符串(“00010000”),需要确定第一个“1”在哪个位置。 (这告诉我客户活跃的月份)
我有一个如下所示的数据集:
id <- c(1:5)
seq <- c("00010000","00001000","01000000","10000000","00010000")
df <- data.frame(id,seq)
我想创建一个新字段来标识每个 ID 的 first_month_active。
我可以使用嵌套的 ifelse 函数手动执行此操作:
df$first_month_active <-
ifelse(substr(df$seq,1,1)=="1",1,
ifelse(substr(df$seq,2,2)=="1",2,
ifelse(substr(df$seq,3,3)=="1",3,
ifelse(substr(df$seq,4,4)=="1",4,
ifelse(substr(df$seq,5,5)=="1",5,99 )))))
这给了我想要的结果:
id seq first_position
1 00010000 4
2 00001000 5
3 01000000 2
4 10000000 1
5 00010000 4
但是,这不是我的数据的理想解决方案,它包含 36 个月。
我想使用带有 ifelse 语句的循环,但是我真的很难理解语法
for (i in 1:36) {
ifelse(substr(df$seq,0+i,0+i)=="1",0+i,
}
任何想法将不胜感激
跳过循环和 ifelse
:
9 - nchar(as.numeric(seq))
## [1] 4 5 2 1 4
这在您的 data.frame 中不会起作用,因为您强制 seq
隐式分解,所以只需执行:
9 - nchar(as.numeric(as.character(df$seq)))
## [1] 4 5 2 1 4
编辑:只是为了好玩,因为 Frank 没有将他的评论转化为答案,这里是 strsplit
解决方案:
# from original vector
sapply(strsplit(seq, "1"), nchar)[1,] + 1
## [1] 4 5 2 1 4
# from data.frame
sapply(strsplit(as.character(df$seq), "1"), nchar)[1,] + 1
## [1] 4 5 2 1 4
或尝试 stringi
套餐
library(stringi)
stri_locate_first_fixed(df$seq, "1")[, 1]
## [1] 4 5 2 1 4
您可以使用 gregexpr
。
> unlist(gregexpr(pattern=1,seq,fixed=T))
[1] 4 5 2 1 4
以下人员可以完成这项工作:
library(stringr)
str_locate(pattern ='1',seq)
另一个,使用log
:
nchar(seq)-round(log10(as.numeric(seq)))
另一个选项使用 sub
nchar(sub('1.*', '', seq))+1
#[1] 4 5 2 1 4
一些比较:
library(stringi)
library(stringr)
seq <- c("00010010","00001000","10000010","10000000","00010000")
seq2 <- rep(seq, 5e6)
system.time(regexpr("1", seq2))
user system elapsed
4.78 0.03 4.82
system.time(9-nchar(as.numeric(as.character(seq2))))
user system elapsed
34.89 0.18 35.52
system.time(str_locate(pattern ='1',seq2))
user system elapsed
6.17 0.21 6.53
system.time(stri_locate_first_fixed(seq2, "1")[, 1])
user system elapsed
1.68 0.15 1.84
system.time(nchar(seq2)-round(log10(as.numeric(seq2))))
user system elapsed
7.67 0.09 7.86
system.time(nchar(sub('1.*', '', seq2))+1)
user system elapsed
14.61 0.11 14.93
我有一个字符串(“00010000”),需要确定第一个“1”在哪个位置。 (这告诉我客户活跃的月份)
我有一个如下所示的数据集:
id <- c(1:5)
seq <- c("00010000","00001000","01000000","10000000","00010000")
df <- data.frame(id,seq)
我想创建一个新字段来标识每个 ID 的 first_month_active。
我可以使用嵌套的 ifelse 函数手动执行此操作:
df$first_month_active <-
ifelse(substr(df$seq,1,1)=="1",1,
ifelse(substr(df$seq,2,2)=="1",2,
ifelse(substr(df$seq,3,3)=="1",3,
ifelse(substr(df$seq,4,4)=="1",4,
ifelse(substr(df$seq,5,5)=="1",5,99 )))))
这给了我想要的结果:
id seq first_position
1 00010000 4
2 00001000 5
3 01000000 2
4 10000000 1
5 00010000 4
但是,这不是我的数据的理想解决方案,它包含 36 个月。
我想使用带有 ifelse 语句的循环,但是我真的很难理解语法
for (i in 1:36) {
ifelse(substr(df$seq,0+i,0+i)=="1",0+i,
}
任何想法将不胜感激
跳过循环和 ifelse
:
9 - nchar(as.numeric(seq))
## [1] 4 5 2 1 4
这在您的 data.frame 中不会起作用,因为您强制 seq
隐式分解,所以只需执行:
9 - nchar(as.numeric(as.character(df$seq)))
## [1] 4 5 2 1 4
编辑:只是为了好玩,因为 Frank 没有将他的评论转化为答案,这里是 strsplit
解决方案:
# from original vector
sapply(strsplit(seq, "1"), nchar)[1,] + 1
## [1] 4 5 2 1 4
# from data.frame
sapply(strsplit(as.character(df$seq), "1"), nchar)[1,] + 1
## [1] 4 5 2 1 4
或尝试 stringi
套餐
library(stringi)
stri_locate_first_fixed(df$seq, "1")[, 1]
## [1] 4 5 2 1 4
您可以使用 gregexpr
。
> unlist(gregexpr(pattern=1,seq,fixed=T))
[1] 4 5 2 1 4
以下人员可以完成这项工作:
library(stringr)
str_locate(pattern ='1',seq)
另一个,使用log
:
nchar(seq)-round(log10(as.numeric(seq)))
另一个选项使用 sub
nchar(sub('1.*', '', seq))+1
#[1] 4 5 2 1 4
一些比较:
library(stringi)
library(stringr)
seq <- c("00010010","00001000","10000010","10000000","00010000")
seq2 <- rep(seq, 5e6)
system.time(regexpr("1", seq2))
user system elapsed
4.78 0.03 4.82
system.time(9-nchar(as.numeric(as.character(seq2))))
user system elapsed
34.89 0.18 35.52
system.time(str_locate(pattern ='1',seq2))
user system elapsed
6.17 0.21 6.53
system.time(stri_locate_first_fixed(seq2, "1")[, 1])
user system elapsed
1.68 0.15 1.84
system.time(nchar(seq2)-round(log10(as.numeric(seq2))))
user system elapsed
7.67 0.09 7.86
system.time(nchar(sub('1.*', '', seq2))+1)
user system elapsed
14.61 0.11 14.93