2015-08-30 41 views
3

cbind名單我有data.frame有效的方式來通過團體data.table

數據

data = structure(list(mystring = c("AASDAASADDLKJLKADDLKKLLKJLJADDLJLKJLADLKLADD", 
    "ASDSDFJSKADDKJSJKDFKSADDLKJFLAK"), class = c("cat", "dog")), .Names = c("mystring", 
    "class"), row.names = c(NA, -2L), class = "data.frame") 

它看起來像

#> dtt1 
#          mystring class 
#1 AASDAASADDLKJLKADDLKKLLKJLJADDLJLKJLADLKLADD cat 
#2    ASDSDFJSKADDKJSJKDFKSADDLKJFLAK dog 

我正在尋找的開始和考慮class作爲組的mystring下字符串的前20個字符中的模式「ADD」的結束位置。

我使用stringrstr_locate這樣做。這是我嘗試

setDT(dtt1)[, 
cbind(list(str_locate_all(substr(as.character(mystring), 1, 20),"ADD")[[1]][,1]), 
     list(str_locate_all(substr(as.character(mystring), 1, 20),"ADD")[[1]][,2])), 
     by = class] 

這讓我所需的輸出

# class V1 V2 
#1: cat 8 10 
#2: cat 16 18 
#3: dog 10 12 

問題: 我想知道,如果這是一個標準的辦法或這樣可以更有效的進行方式。 str_locate給在單獨的列匹配模式的startend職位,我把它們放在單獨的列表cbind他們一起data.table?另外,如何在此處指定colnames用於結合columns

+0

'由= class'需要? – Khashaa

+0

@Khashaa是在問題的標題中。我想通過小組 –

回答

4

我認爲你首先應該減少你的每個組的操作,所以我首先要爲所有組創建一個子串。

setDT(data)[, submystring := .Internal(substr(mystring, 1L, 20L))] 

然後,使用stringi包(我不喜歡包裝),你可以這樣做(儘管目前還不能擔保效率)

library(stringi) 
data[, data.table(matrix(unlist(stri_locate_all_fixed(submystring, "ADD")), ncol = 2)), by = class] 
# class V1 V2 
# 1: cat 8 10 
# 2: cat 16 18 
# 3: dog 10 12 

另外,您可避免每個組呼叫matrixdata.table,但在檢測到所有位置後傳播數據

res <- data[, unlist(stri_locate_all_fixed(submystring, "ADD")), by = class] 
res[, `:=`(varnames = rep(c("V1", "V2"), each = .N/2), MatchCount = rep(1:(.N/2), .N/2)), by = class] 
dcast(res, class + MatchCount ~ varnames, value.var = "V1") 
# class MatchCount V1 V2 
# 1: cat   1 8 10 
# 2: cat   2 16 18 
# 3: dog   1 10 12 

三類似的選項可能是先試運行stri_locate_all_fixed整個數據集,然後才每組unlist(而不是同時運行和unliststri_locate_all_fixed每組)

res <- data[, .(stri_locate_all_fixed(submystring, "ADD"), class = class)] 
res[, N := lengths(V1)/2L] 
res2 <- res[, unlist(V1), by = "class,N"] 
res2[, `:=`(varnames = rep(c("V1", "V2"), each = N[1L]), MatchCount = rep(1:(N[1L]), N[1L])), by = class] 
dcast(res2, class + MatchCount ~ varnames, value.var = "V1") 
# class MatchCount V1 V2 
# 1: cat   1 8 10 
# 2: cat   2 16 18 
# 3: dog   1 10 12 
+1

感謝您的好解決方案!(+1)我正在檢查我的原始龐大數據集中的答案效率 –

3

我們可以改變的matrixstr_locate_all輸出到data.frame並使用rbindlist來創建列。

setDT(data)[,rbindlist(lapply(str_locate_all(substr(mystring, 1, 20), 
       'ADD'), as.data.frame)) , class] 
    # class start end 
    #1: cat  8 10 
    #2: cat 16 18 
    #3: dog 10 12 
+0

感謝您的好解決方案! (+1)我正在檢查我的原始龐大數據集中的答案的效率 –

+0

@VeerendraGadekar感謝您的評論 – akrun

+1

它對我的數據集非常合適。雖然我正在使用dcast方法(David的第二種方法),但由於三步驟地完成任務,我發現速度更快。 –

2

這就是我做到的。

library(stringi) 
library(dplyr) 
library(magrittr) 

data = structure(list(mystring = c("AASDAASADDLKJLKADDLKKLLKJLJADDLJLKJLADLKLADD", 
            "ASDSDFJSKADDKJSJKDFKSADDLKJFLAK"), class = c("cat", "dog")), .Names = c("mystring", 
                              "class"), row.names = c(NA, -2L), class = "data.frame") 

my_function = function(row) 
    row$mystring %>% 
    stri_sub(to = 20) %>% 
    stri_locate_all_fixed(pattern = "ADD") %>% 
    extract2(1) %>% 
    as_data_frame 

test = 
    data %>% 
    group_by(mystring) %>% 
    do(my_function(.)) %>% 
    left_join(data)