Reduce a data frame to fewer rows
假设我有一个数据框"dat",例如:
1 2 3 4 5 6 7 8 9 10 11 | col1 col2 12 a 43 a 54 a 11 a 33 b 43 b 34 c 34 c 342 c 343 c |
现在我有一个向量作为
1 | vec <- c(a,a,a,b,c,c) |
我想要做的是根据向量"vec"删除数据框"dat"中的额外行,这意味着在数据框中只保留与"a"对应的前3行,只保留与 "b" 对应的前 1 行,只保留与 c.
对应的前 2 行
我应该得到
的输出
1 2 3 4 5 6 7 | col1 col2 12 a 43 a 54 a 33 b 34 c 34 c |
不用for循环最快的方法是什么?
这也可以在创建序列列之后完成
1 2 3 4 5 6 7 8 9 10 | library(data.table) setkey(setDT(dat)[, N:= 1:.N, col2], col2, N) dat[setDT(list(col2=vec))[, N:=1:.N, col2]][, N:= NULL][] # col1 col2 #1: 12 a #2: 43 a #3: 54 a #4: 33 b #5: 34 c #6: 34 c |
这是另一种
1 2 3 4 5 6 7 8 9 10 11 12 | fvec <- factor(vec) ## find the index for the first occurrence of a new level m <- match(levels(fvec), df$col2) df[unlist(Map(seq, from = m, length.out = tabulate(fvec))), ] # col1 col2 # 1 12 a # 2 43 a # 3 54 a # 5 33 b # 7 34 c # 8 34 c |
或者你可以在匹配
之后使用
1 2 3 4 5 6 7 8 9 | rl <- rle(match(vec, df$col2)) df[unlist(Map(seq, rl$values, length.out = rl$lengths)),] # col1 col2 # 1 12 a # 2 43 a # 3 54 a # 5 33 b # 7 34 c # 8 34 c |
使用
1 2 3 4 5 6 | #create a data frame with frequencies tv <- data.frame(table(vec)) #filter values group_by(dat, col2) %>% filter(row_number() <= tv$Freq[tv$vec %in% col2]) |
给出:
1 2 3 4 5 6 7 8 9 10 | #Source: local data frame [6 x 2] #Groups: col2 # # col1 col2 #1 12 a #2 43 a #3 54 a #4 33 b #5 34 c #6 34 c |
这是一种使用
数据
1 2 3 4 5 6 7 8 9 10 11 12 13 | dat <- read.table(header=T, text=' col1 col2 12 a 43 a 54 a 11 a 33 b 43 b 34 c 34 c 342 c 343 c',stringsAsFactors=F) vec <- c('a','a','a','b','c','c') |
解决方案
1 2 3 4 5 6 7 8 9 | #count frequencies tabvec <- table(vec) data.frame(do.call(rbind, #use split to split data.frame according to col2 #use head to only choose the first n rows according to tabvec #convert output into a data.frame Map(function(x,y) head(x,y), split(dat, as.factor(dat$col2)), tabvec) )) |
输出:
1 2 3 4 5 6 7 | col1 col2 a.1 12 a a.2 43 a a.3 54 a b 33 b c.7 34 c c.8 34 c |