R数据框:按组对列中的字符串在行之间聚合

5

我有一个看起来非常低效的解决方案,用于解决一个奇特的问题。我有文本数据,由于各种原因,在数据帧的行之间以随机间隔分裂。然而,基于数据帧中其他变量的唯一组合,某些子集是已知归属于一起的。例如,请参见演示结构和我的初始解决方案的MWE:

# Data
df <- read.table(text="page passage  person index text
1  123   A   1 hello      
1  123   A   2 my
1  123   A   3 name
1  123   A   4 is
1  123   A   5 guy
1  124   B   1 well
1  124   B   2 hello
1  124   B   3 guy",header=T,stringsAsFactors=F)

master<-data.frame()
for (i in 123:max(df$passage)) {
  print(paste0('passage ',i))
  tempset <- df[df$passage==i,]
  concat<-''
  for (j in 1:nrow(tempset)) {
    print(paste0('index ',j))
    concat<-paste(concat, tempset$text[j])
  }
  tempdf<-data.frame(tempset$page[1],tempset$passage[1], tempset$person[1], concat, stringsAsFactors = FALSE)
  master<-rbind(master, tempdf)
  rm(concat, tempset, tempdf)
}
master
> master
  tempset.page.1. tempset.passage.1. tempset.person.1.                concat
1               1                123                 A  hello my name is guy
2               1                124                 B        well hello guy

在这个例子中,就像在我的真实案例中一样,“passage”是唯一的分组变量,因此并不完全需要将其他部分与其一起带出来,尽管我希望它们在我的数据集中可用。
我的目前估计是,我所设计的这个过程将花费几个小时来处理一个在我的电脑上很容易处理的数据集。也许可以通过其他函数或包获得一些效率,或者不要创建和删除那么多对象?
感谢任何帮助!
2个回答

9

data.table 的一个示例:

require(data.table)
DT <- data.table(df)

DT[,.(concat=paste0(text,collapse=" ")),by=.(page,passage,person)]
#    page passage person               concat
# 1:    1     123      A hello my name is guy
# 2:    1     124      B       well hello guy

除了passage之外的其他变量放在by中并不会花费太多,我觉得。


dplyr的类比是

df %>% 
  group_by(page,passage,person) %>% 
  summarise(concat=paste0(text,collapse=" "))

# Source: local data frame [2 x 4]
# Groups: page, passage, person
# 
#   page passage person               concat
# 1    1     123      A hello my name is guy
# 2    1     124      B       well hello guy

基础 R 的一种方法是:

df$concat <- with(df,ave(text,passage,FUN=function(x)paste0(x,collapse=" ")))
unique(df[,which(names(df)%in%c("page","passage","person","concat"))])
#   page passage person               concat
# 1    1     123      A hello my name is guy
# 6    1     124      B       well hello guy

3
不错的回答,+1。不过有一件事:为什么不使用 DT[, .(concat=paste0(... 这样数据表的答案就像其他答案一样有一个明确标记的列呢? - arvi1000

4
这里有两种方式:
基于R语言的方法:
aggregate(
    text ~ page + passage + person, 
    data=df, 
    FUN=paste, collapse=' '
)

dplyr

library(dplyr)
df %>% 
    group_by_(~page, ~passage, ~person) %>%
    summarize_(text=~paste(text, collapse=' '))

不需要使用 select~_ 是做什么的?同样地,你不需要对 aggregate 进行子集操作,data=df 似乎可以工作。 - Frank
1
谢谢,你说得对。请查看vignette('nse', package='dplyr') - Matthew Plourde
我选择了这个答案,因为它稍微简单一些,并且使用了基础知识——虽然其他答案同样有效。感谢大家! - SOConnell

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接