2015-10-15 66 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我不认为运行一个'应用'的边距是必要的或任何改进 –

相关问题