我有一个看起来像这样的数据框:
data <- data.frame(label = c('S', 'SH', 'S', 'S', 'SH'),
word = c('sip', 'shoe', 'plaster', 'reception', 'reception'),
word.segs = c('S IH1 P', 'SH UW1', 'P L AE1 S T AH0', 'R AH0 S EH1 P SH AH0 N', 'R AH0 S EH1 P SH AH0 N'),
seg.index = c(1, 1, 4, 3, 6))
'word.segs'在'word'列中包含单词的语音注音,并且'seg.index'中的值指的是感兴趣的片段,即该转录的第n个片段。我想做的是创建两个包含之后这两个段的新列,即seg.index + 1和seg.index + 2。
我已经在以下循环中尝试过该方法,该方法可以工作,但是绝对需要花很多时间(并且我有10万行,因此在这里有一个有效的解决方案很重要)
for (x in 1:nrow(data)){
data[x, ]$fol.seg = unlist(data$word.segs[x])[data[x, ]$seg.index+1]
data[x, ]$fol.seg2 = unlist(data$word.segs[x])[data[x, ]$seg.index+2]
}
(请注意,我也只尝试了取消列表一次,将其保存到一个单独的对象中,然后提取两个感兴趣的值,但这似乎并不快得多)
我还尝试了dplyr中的替代方法,希望它可能更有效:
data <- data %>%
mutate(fol.seg = word.segs %>%
strsplit(split = " ") %>%
unlist() %>%
nth(seg.index+1))
但是我收到以下错误消息,我也不知道为什么它不起作用:
mutate_impl(.data,点)中的错误: 评估错误:length(n)== 1不是TRUE。
任何帮助将不胜感激!
答案 0 :(得分:2)
这仅在使用基数R的情况下有效。您也许可以通过purrr
来实现它。
library(dplyr)
try_pull = function(x, i) {
if (i > length(x)) NA else x[[i]]
}
res = data %>%
mutate(seg_list = strsplit(word.segs, split = " "),
seg1 = Map(f = try_pull, seg_list, seg.index + 1),
seg2 = Map(f = try_pull, seg_list, seg.index + 2)
)
res
# label word word.segs seg.index seg_list seg1 seg2
# 1 S sip S IH1 P 1 S, IH1, P IH1 P
# 2 SH shoe SH UW1 1 SH, UW1 UW1 NA
# 3 S plaster P L AE1 S T AH0 4 P, L, AE1, S, T, AH0 T AH0
# 4 S reception R AH0 S EH1 P SH AH0 N 3 R, AH0, S, EH1, P, SH, AH0, N EH1 P
# 5 SH reception R AH0 S EH1 P SH AH0 N 6 R, AH0, S, EH1, P, SH, AH0, N AH0 N
答案 1 :(得分:1)
另一种dplyr
可能性是:
data %>%
rowwise() %>%
mutate(seg1 = sapply(strsplit(as.character(word.segs), " "), function(x) x[seg.index + 1]),
seg2 = sapply(strsplit(as.character(word.segs), " "), function(x) x[seg.index + 2]))
label word word.segs seg.index seg1 seg2
<fct> <fct> <fct> <dbl> <chr> <chr>
1 S sip S IH1 P 1 IH1 P
2 SH shoe SH UW1 1 UW1 <NA>
3 S plaster P L AE1 S T AH0 4 T AH0
4 S reception R AH0 S EH1 P SH AH0 N 3 EH1 P
5 SH reception R AH0 S EH1 P SH AH0 N 6 AH0 N
在这里,它用strsplit()
分割“ word.segs”,然后使用sapply()
选择所需的元素。
或者使用您原始帖子中的想法:
data %>%
rowwise %>%
mutate(seg1 = strsplit(as.character(word.segs), " ") %>%
unlist() %>%
nth(seg.index + 1),
seg2 = strsplit(as.character(word.segs), " ") %>%
unlist() %>%
nth(seg.index + 2))
答案 2 :(得分:0)
以下data.table方法应既快速又灵活,以便在seg.index之后或仅在前两个之后选择所有segs
library(data.table)
data <- data.frame(label = c('S', 'SH', 'S', 'S', 'SH'),
word = c('sip', 'shoe', 'plaster', 'reception', 'reception'),
word.segs = c('S IH1 P', 'SH UW1', 'P L AE1 S T AH0', 'R AH0 S EH1 P SH AH0 N', 'R AH0 S EH1 P SH AH0 N'),
seg.index = c(1, 1, 4, 3, 6),stringsAsFactors = F)
data$id <- 1:nrow(data)
dt <- as.data.table(data,stringsAsFactors=F)
setkeyv(dt,"id")
segdt<-dt[,list(seg.index=seg.index,seg=unlist(strsplit(word.segs,"\\s+"))),by="id"][,n:=1:.N,by="id"]
segdt<-segdt[n>seg.index][,`:=`(seg.col=paste0("seg",1:.N),seg.num=1:.N),by="id"]
#dt[segdt[,list(index.word.segs=paste(seg,collapse=",")),by="id"]] #rejoin original table and all segs after seg.index
widesegs <- dcast.data.table(segdt[seg.num<=2,.(id,seg,seg.col)],id ~ seg.col,value.var="seg") #only first two segs after seg.index or NA
dt[widesegs]
结果:
> dt[widesegs]
label word word.segs seg.index id seg1 seg2
1: S sip S IH1 P 1 1 IH1 P
2: SH shoe SH UW1 1 2 UW1 NA
3: S plaster P L AE1 S T AH0 4 3 T AH0
4: S reception R AH0 S EH1 P SH AH0 N 3 4 EH1 P
5: SH reception R AH0 S EH1 P SH AH0 N 6 5 AH0 N
要使所有细分均大于seg.index:
widesegs <- dcast.data.table(segdt[,.(id,seg,seg.col)],id ~ seg.col,value.var="seg") #all segs after seg.index or NA
dt[widesegs]
> dt[widesegs]
label word word.segs seg.index id seg1 seg2 seg3 seg4 seg5
1: S sip S IH1 P 1 1 IH1 P NA NA NA
2: SH shoe SH UW1 1 2 UW1 NA NA NA NA
3: S plaster P L AE1 S T AH0 4 3 T AH0 NA NA NA
4: S reception R AH0 S EH1 P SH AH0 N 3 4 EH1 P SH AH0 N
5: SH reception R AH0 S EH1 P SH AH0 N 6 5 AH0 N NA NA NA