Substring a row column in datatable using positions from another column

I have a data table that contains several columns of the following type:

   attr1 attr2
1: 01001 01000
2: 11000 10000
3: 00100 00100
4: 01100 01000

DT = setDT(structure(list(attr1 = c("01001", "11000", "00100", "01100"), 
    attr2 = c("01000", "10000", "00100", "01000")), .Names = c("attr1", 
"attr2"), row.names = c(NA, -4L), class = "data.frame"))

All columns are rows not numbers. What I would like to achieve is the following:

1) I want to find the positions that "1" appears in the attr1 lines

2) Take the attr2 values ​​in these positions

My result in this case would be:

[1] "10" "10" "1"  "10"

As an example, in the first line, attr1 has "1" at positions 2 and 5, I multiply the first line of attr2 at positions 2 and 5 and ending with "10".

What I was thinking of doing is strsplit the columns and then working with it, but I really hope that there is a better way.

+4
source share
3

base R regmatches :

dt[, matches := sapply(regmatches(attr2, gregexpr('1+', attr1)), paste, collapse = '')][]
#>    attr1 attr2 matches
#> 1: 01001 01000      10
#> 2: 11000 10000      10
#> 3: 00100 00100       1
#> 4: 01100 01000      10

dt <- structure(list(attr1 = c("01001", "11000", "00100", "01100"), 
        attr2 = c("01000", "10000", "00100", "01000")), .Names = c("attr1", 
    "attr2"), row.names = c(NA, -4L), class = "data.frame")

setDT(dt)
+7

@alistaire regmatches, regmatches<-. , 1 0 "":

dt[, matches := `regmatches<-`(attr2, gregexpr("0+", attr1), value="")]

#   attr1 attr2 matches
#1: 01001 01000      10
#2: 11000 10000      10
#3: 00100 00100       1
#4: 01100 01000      10

strsplit :

dt[, matches := mapply(function(x,y) paste(y[x==1],collapse=""), strsplit(attr1,""), strsplit(attr2,""))]
+9

worked on it and then saw @latemail comments

library(data.table)
DT = setDT(structure(list(attr1 = c("01001", "11000", "00100", "01100"),
    attr2 = c("01000", "10000", "00100", "01000")), .Names = c("attr1",
        "attr2"), row.names = c(NA, -4L), class = "data.frame"))

set.seed(0L)
N <- 1e5
dt <- data.table(attr1=do.call(paste0, data.frame(matrix(sample(0:1, N*5, replace=TRUE), ncol=5))),
    attr2=do.call(paste0, data.frame(matrix(sample(0:1, N*5, replace=TRUE), ncol=5))))

func_woSapply <- function() {
    dt1 <- copy(dt)
    dt1[, matches := `regmatches<-`(attr2, gregexpr("0+", attr1), value="")]
    dt1
}

func_withSapply <- function() {
    dt2 <- copy(dt)
    dt2[, matches := sapply(regmatches(attr2, gregexpr('1+', attr1)), paste, collapse = '')]
    dt2
}

func_useLogical <- function() {
    dt3 <- copy(dt)
    dt3[, matches := {
            d <- lapply(.SD, strsplit, "")
            lapply(mapply(function(x, y) y[as.logical(as.numeric(x))],
                d[["attr1"]], d[["attr2"]], SIMPLIFY=TRUE), paste, collapse="")
        }]
    dt3
}

library(stringi)
func_stringi <- function() {
    dt4 <- copy(dt)
    dt4[, matches := stri_c_list(Map(stri_sub, attr2, stri_locate_all_regex(attr1, '1+')))]
    dt4
}

func_indexing <- function() {
    dt[, mapply(function(x,y) paste(y[x==1],collapse=""), strsplit(attr1,""), strsplit(attr2,""))]
}

library(microbenchmark)
microbenchmark(
    func_woSapply=func_woSapply(),
    func_withSapply=func_withSapply(),
    func_useLogical=func_useLogical(),
    func_stringi=func_stringi(),
    func_indexing=func_indexing(),
    times=10L)

# Unit: milliseconds
#            expr       min        lq      mean    median        uq       max neval
#   func_woSapply 2167.8063 2167.8063 2167.8063 2167.8063 2167.8063 2167.8063     1
# func_withSapply 1693.5539 1693.5539 1693.5539 1693.5539 1693.5539 1693.5539     1
# func_useLogical 1317.5950 1317.5950 1317.5950 1317.5950 1317.5950 1317.5950     1
#    func_stringi  598.3469  598.3469  598.3469  598.3469  598.3469  598.3469     1
#   func_indexing  816.8548  816.8548  816.8548  816.8548  816.8548  816.8548     1
+3
source

Source: https://habr.com/ru/post/1674703/


All Articles