2015-10-15 69 views
3

讓我們假設以下爲我的數據表data函數應用到列的每個元素單獨

data <- setDT(structure(list(col1 = c(1, 2, 3, 4, 5), col2 = c(53, 45, 54, 
97, 23), col3 = c("aa aa aa aa ab ad af ae ar", "bb bb bb bb bt by bu bi bo", 
"cc cc cc cc cd cy ch cn cd", "dd dd dd dd dt dy dj dk da", "ee ee ee ee et eh es er eg" 
), col4 = c("aa bb ff ff","aa ff vv rr","dd dd rr gg", 
"yy yy rr rr","uu uu uu ee")), .Names = c("col1", "col2", "col3", "col4"), 
row.names = c(NA, -5L), class = "data.frame")) 

col1  col2 col3       col4 
1  53  aa aa aa aa ab ad af ae ar  aa bb ff ff 
2  45  bb bb bb bb bt by bu bi bo  aa ff vv rr 
3  54  cc cc cc cc cd cy ch cn cd  dd dd rr gg 
4  97  dd dd dd dd dt dy dj dk da  yy yy rr rr 
5  23  ee ee ee ee et eh es er eg  uu uu uu ee 

col3有詞的字符串,我需要找到,如果最頻繁發生word在COL3出現在或者不是。因此,輸出將類似於如下:

col1  col2 col3       col4   most_freq_word_in_cool3  out_col 
1  53  aa aa aa aa ab ad af ae ar  aa bb ff ff    aa      1 
2  45  bb bb bb bb bt by bu bi bo  aa ff vv rr    bb      0 
3  54  cc cc cc cc cd cy ch cn cd  dd dd rr gg    cc      0 
4  97  dd dd dd dd dt dy dj dk da  yy yy rr rr    dd      0 
5  23  ee ee ee ee et eh es er eg  uu uu uu ee    ee      1 

我嘗試以下解決方案

m_fre_word1 <- function(x) { string <- as.character(unlist(strsplit(x, " "))) 
           freq <- sort(table(string), decreasing = T) 
           wr <-names(freq)[1] 
           return(wr) } 

    data <- data[ , most_freq_word_in_cool3:= apply(data[ , .(col3)], 1, m_fre_word1)] 
    data <- data[ , out_col:= as.numeric(grepl(m_fre_word1(col3), col4))] 

有沒有錯的解決方案是,但它實在是太慢了。我的數據表很龐大。我不能用這種方式,所以我正在尋找更快的選擇。有人可以建議一個更快的選擇。

謝謝,

+0

爲了使這個容易複製,發佈'dput'的數據幀。 –

+0

@PierreLafortune我該怎麼做? – user3664020

+0

'dput(data)'它看起來像'structure(....(data.table))' –

回答

2

這是一個嘗試。與其在每一行上運行這整個事情,我都會建議拆分該列並以長格式進行操作。

我偷了從hereMode功能,它被定義爲使用最新版本data.table如下

Mode <- function(x) { 
    ux <- unique(x) 
    ux[which.max(tabulate(match(x, ux)))] 
} 

現在我們可以做

library(data.table) # v 1.9.6+ 
temp <- setDT(data6)[, tstrsplit(col3, " ", fixed = TRUE)] 
data6[, res := melt(temp[, indx := .I], id = "indx")[, Mode(value), by = indx]$V1] 
data6 

# col1 col2      col3  col4 res 
# 1: 1 53 aa aa aa aa ab ad af ae ar aa bb ff ff aa 
# 2: 2 45 bb bb bb bb bt by bu bi bo aa ff vv rr bb 
# 3: 3 54 cc cc cc cc cd cy ch cn cd dd dd rr gg cc 
# 4: 4 97 dd dd dd dd dt dy dj dk da yy yy rr rr dd 
# 5: 5 23 ee ee ee ee et eh es er eg uu uu uu ee ee 

第二步可以通過eitehr輕鬆實現

data6[, out := +grepl(res, col4, fixed = TRUE), by = res] 

OR(不知道哪一個是更快)

library(stringi) 
data6[stri_detect_fixed(col4, res), out := 1L] 

作爲一個側面說明,使用引用語義時,沒有必要複製整個數據集,並使用<-重新分配,實際上這就是引用語義的全部要點。請閱讀this

+0

可能的是,stringi會爲您提供NA而不是零。可以在它之前添加一個'[,out:= 0L]'。 – Frank

+1

@Frank我知道,我認爲這並不重要,因爲它很容易修復,或者OP可以用'!is.na(out)'或'sum(out,na.rm = TRUE)'來過濾或者相似的東西。 –

2

我認爲apply(data[ , .(col3)]是減慢你的代碼。通常我發現在data.table調用中放置一個子集會導致巨大的減速,因爲子集操作很昂貴。

你可以試試:

DT[ , test := names(sort(table(strsplit(col3," ")), decreasing = T))[1], by = col1] 
DT[, search := gsub(" ","|",col4)] 
DT[, output := grepl(search,test), by = col1] 

不知道如果我還是大衛的回答會更快。

編輯:根據弗蘭克的輸入,最後兩行可以替換爲:

DT[, output := mapply(grepl,gsub(" ","|",col4),test)] 
+0

跳過'by'(並創建一個'search' col)可以提高速度:'DT [,output:= mapply(grepl,gsub(「」,「|」,col4),test)]''。另外,我猜'tabulate'比'table'快,如果你可以計算如何切換。 – Frank

+1

冉microbenchmark,你是對的。獲得一條線是最大的改進,然後通過替換來增加一點點。編輯以反映 – Chris

+0

@Chris爲什麼我們在第一個陳述中需要'by = col1'? – user3664020

1

(編輯按下面的評論)

加載庫

require(data.table) 

定義數據

x <- 
    data.table(
    col1 = c(1, 2, 3, 4, 5), 
    col2 = c(53, 45, 54, 97, 23), 
    col3 = c(
     "aa aa aa aa ab ad af ae ar", "bb bb bb bb bt by bu bi bo", 
     "cc cc cc cc cd cy ch cn cd", "dd dd dd dd dt dy dj dk da", 
     "ee ee ee ee et eh es er eg"), 
    col4 = c(
     "aa bb ff ff","aa ff vv rr","dd dd rr gg", 
     "yy yy rr rr","uu uu uu ee") 
     ) 

找到最freqent元素COL3

x[,most_freq_word_in_col3:=sapply(col3,function(e){ 
    names(sort(table(unlist(strsplit(e," "))),decreasing=TRUE)[1])})] 

檢查是否COL4此元素

x[,out_col:=apply(cbind(most_freq_word_in_col3,col4),1,function(e){ 
    as.numeric(e[1] %in% unlist(strsplit(e[2]," ")))})] 

輸出:

> x 
    col1 col2      col3  col4 most_freq_word_in_col3 out_col 
1: 1 53 aa aa aa aa ab ad af ae ar aa bb ff ff      aa  1 
2: 2 45 bb bb bb bb bt by bu bi bo aa ff vv rr      bb  0 
3: 3 54 cc cc cc cc cd cy ch cn cd dd dd rr gg      cc  0 
4: 4 97 dd dd dd dd dt dy dj dk da yy yy rr rr      dd  0 
5: 5 23 ee ee ee ee et eh es er eg uu uu uu ee      ee  1 
+0

這已經由Chris –

+0

發佈了@DavidArenburg第二部分是不同的,'%in%'而不是正則表達式。 – Frank

+0

@Frank我不認爲運行一個'應用'的邊距是必要的或任何改進 –

相關問題