R:快速系统地删除这样的行?

时间:2018-03-19 21:04:13

标签: r

我有一个包含单列的数据框。

有620行。前31行标记为" A",接下来的31行标记为" B类和#34;等等。因此有20个班级。

我想做的事情很容易解释,但我需要帮助编码。

在第一次迭代中,我想删除与每个类的最后一行对应的所有行。也就是说,删除最后一个" A类"行,然后删除最后一个" B类行",依此类推。必须执行此迭代以及所有其他迭代,因为我打算使用新创建的数据集执行其他操作。

在第二次迭代中,我想删除与每个类的最后两行对应的所有行。因此,删除" A类"的最后两行,最后两行为" B class"等等。

在第三次迭代中,删除每个类的最后三行。等等。

在最后一次迭代中,我们删除每个类的最后30行。基本上我们每次观察只保留1行,第一行。

将这个放入R代码的快速方法是什么?我知道我需要使用for循环并仔细选择一些索引来删除,但是如何?

实施例

column
A1
A2
A3
B1
B2
B3

如果上面是我们的原始数据框,那么在第一次迭代中,我们应该留下

column
A1
A2
B1
B2

等等。

4 个答案:

答案 0 :(得分:0)

我在这里做的很简单,使用n = 3而不是n = 31这个虚拟数据集

n <- 3
dummy <- c(rep("A", n), rep("B", n), rep("C", n))

> dummy
[1] "A" "A" "A" "B" "B" "B" "C" "C" "C"

现在,诀窍是使用布尔索引来选择每次迭代要保留的值,并将其与R将重复索引向量的特征结合起来,以便短矢量匹配更长的向量所需的时间。

此函数创建一个掩码,应该选择组中的元素

make_mask <- function(to_keep, n)
    c(rep(TRUE, to_keep), rep(FALSE, n - to_keep))

它只是给你一个布尔矢量

> make_mask(2, 3)
[1]  TRUE  TRUE FALSE

我们可以在一个为迭代选择元素的函数中使用它:

pick_subset <- function(to_keep) dummy[make_mask(n - to_keep, n)]

现在,您可以在循环或lapply中使用它来获取每次迭代所需的元素。

iterations <- iterations <- lapply(0:(n-1), pick_subset)

会给你这个

> iterations
[[1]]
[1] "A" "A" "A" "B" "B" "B" "C" "C" "C"

[[2]]
[1] "A" "A" "B" "B" "C" "C"

[[3]]
[1] "A" "B" "C"

如果在lapply中使用1:n更符合您的口味,只需调整make_mask即可进行补偿。

答案 1 :(得分:0)

 dat%>%mutate(grp=sub("\\d","",column))%>%
       group_by(grp)%>%
        slice(-n())%>%
      ungroup()%>%select(-grp)
# A tibble: 4 x 1
  column
   <chr>
1     A1
2     A2
3     B1
4     B2

数据:

dat=read.table(header = T,stringsAsFactors = F,text="column
A1
           A2
           A3
           B1
           B2
           B3")

答案 2 :(得分:0)

还有另一种方式。假设代码全部按照您显示的方式进行分组和排序,请使用public class ClassRemove : RemoveInfinite<object> { public override object Remove() { return new object(); } } public class ClassA : SomeBaseClass, IRemove<object> { private RemoveInfinite<object> removeInfinite = new ClassRemove(); public object Remove() { return removeInfinite.Remove(); } public bool IsCompleted { get { return removeInfinite.IsCompleted; } } } 函数获取列中的代码数。 table cumsum中的每个值恰好对应于每个序列中最后一项的索引。每次循环时table变量都会增加1。通过删除由indexes索引的行来创建y变量。 (indexes未排序并不重要。)您只需使用indexes执行所需操作即可。这是带有示例data.frame:

的代码
y

N <- 31 dat <-data.frame(x=c(rep("A",31),rep("B",31),rep("C",31),rep("D",31),rep("E",31))) t.x <- cumsum(table(dat$x)) for (i in 1:(N-1)) { if (i == 1){ indexes <- t.x } else { indexes = c(indexes,t.x-i) } y <- dat$x[-indexes] print(table(y)) } 将显示每个代码的计数将根据需要减少。

print(table(y))

答案 3 :(得分:0)

使用data.table包

的解决方案

因为您确切地知道每个类中有多少项以及数据中存在多少个类,所以以下简单的解决方案有效:

导入包并生成一些测试数据:

rm(list=ls())
library(data.table) 

A = rep('A', 3) 
B = rep('B', 3) 
C = rep('C', 3)
val = rep(1:3, 3)

DT = data.table(class=c(A,B,C), val=val)

这个循环只是迭代了每个所谓的“类”中的项目的次数。在每次迭代中,我们使用.SD[1:(4-i)]部分代码将越来越小的原始数据子集。一定要设置一个值(在这种情况下为4),这个值比每个类中的数字项多一个,这样就不会收到“索引超出范围错误”。很酷的部分是data.table允许我们通过分组向量(在这种情况下为“类”)来完成此操作。

for(i in 1:3) {
  print(DT[, .SD[1:(4-i)], by = class])  # edit as needed to save copies
}

输出:

   class val
1:     A   1
2:     A   2
3:     A   3
4:     B   1
5:     B   2
6:     B   3
7:     C   1
8:     C   2
9:     C   3
   class val
1:     A   1
2:     A   2
3:     B   1
4:     B   2
5:     C   1
6:     C   2
   class val
1:     A   1
2:     B   1
3:     C   1