R根据条件删除行(高级)
R deleting rows based on condition (advanced)
我有一些非常大的数据框,我创建了一个条件列,它可以是 10、1、60 或 70,具体取决于某些特定值。介于两者之间的所有内容都是 0。然后我创建了一个小数据框,每隔 10 和 70 个位置(我想要的每个序列的开始和结束)并设法对我的数据框进行子集化,这样我只剩下每个 10 和 70 之间的内容(包括它们之间的 1、60 和 0)。
生成的数据框几乎是我需要的子集,条件列现在如下所示:
condition
10
0
0
1
0
0
0
60
0
0
70
10
0
0
1
0
60
0
0
70
0
0
10
0
0
1
0
0
60
0
0
70
0
10
0
0
1
0
0
0
0
60
0
0
0
70
每次70后,我应该再得到10,并重复每个循环。但是,当我在一夜之间对多个文件的循环设置此过程时,结果包含一些不需要的数据。正如您在上面看到的,70 到 10 之间有行。我想消除所有 70 到 10 之间的 0 行。在这个例子中,每个非零值之间只有几行,但我的实际数据远不止于此。
所以从上面得到的数据框将是:
condition
10
0
0
1
0
0
0
60
0
0
70
10
0
0
1
0
60
0
0
70
10
0
0
1
0
0
60
0
0
70
10
0
0
1
0
0
0
0
60
0
0
0
70
这些数据帧的范围从 1 到 1000 万行,因此我认为设置查看每一行并迭代的外观不会很有效。有什么想法吗?
UPDATE
我认为我有一个解决方案,使用的方法与我到达这里时所用的方法相同。
我试过了:
test$t = NA
test$t = ifelse(shift(test$ff== 70) & test$ff != 10, 1, test$t)
test$t = ifelse(shift(test$ff== 10, type = "lead") & test$ff != 70, 1, test$t)
test2 = data.frame(s = test$t[c(T,F)], e = test$t[c(F,T)])
Error in data.frame(s = test$t[c(T, F)], e = test$t[c(F, T)]) :
arguments imply differing number of rows: 44085, 44084
我的想法是找到每个 'bad' 70 之后和每个 'bad' 10 之前的行,然后删除使用 test2 之间的所有位置。它失败了,因为我的数据也有这样的情况:
70
0
0
60
0
0
70
10
这里没有配对 'bad' 10 代表 70。想一想,如果不是尝试删除坏的东西,而是使用我原来的方法再次子集,即仅从 10 - 70 中查找序列,我可能会解决它。我这样做的方式如下:
df2 = df[df$ff == 10 | df$ff == 70,]
test = data.frame(s = df2$datetime[c(T,F)], e = df2$datetime[c(F,T)])
for(i in 1:length(test$s)){test$ss[i] = which(df$datetime == test$s[i])}
for(i in 1:length(test$s)){test$ee[i] = which(df$datetime == test$e[i])}
for(i in 1:length(test$s)){df$t[test$ss[i]:test$ee[i]] = 1}
df_all= df[df$t ==1,]
高级吧?
zoo::na.locf
是你的朋友:
condition <- as.numeric(c("10", "0", "0", "1", "0", "0", "0", "60",
"0", "0", "70", "10", "0", "0", "1", "0", "60", "0", "0", "70",
"0", "0", "10"))
dfr <- data.frame(condition = condition)
dfr$between <- NA
dfr$between[dfr$condition == 70] <- TRUE
dfr$between[dfr$condition == 10] <- FALSE
dfr$between <- zoo::na.locf(dfr$between, na.rm = FALSE)
dfr$between[dfr$condition == 70] <- FALSE # don't remove the 70s themselves
dfr[! dfr$between, ]
假设您的条件 data.frame 称为 test
。
start_end<-data.frame(a=which(test$condition==10),b=which(test$condition==70))
得到一个 data.frame 标记每个开始和每个结束
获取生成序列的函数
fun.seq<-function(a,b){
return(seq(a,b,1))
}
将该函数应用于 start_end 的每一行并将其取消列出,select 行
test[unlist(mapply(fun.seq,start_end$a,start_end$b)),]
[1] 10 0 0 1 0 0 0 60 0 0 70 10 0 0 1 0 60 0 0 70 10 0 0 1 0 0 60 0 0 70 10 0 0 1 0 0 0 0 60 0 0 0 70
我不确定它在数百万行上是否足够快。
也许 data.table 可以更快地完成此操作,但我不确定该怎么做。
我想出了这个非常俗气的方法,简单但有效。
mapply 的输出:
mapply(fun.seq,start_end$a,start_end$b)
[[1]]
[1] 1 2 3 4 5 6 7 8 9 10 11
[[2]]
[1] 12 13 14 15 16 17 18 19 20
[[3]]
[1] 23 24 25 26 27 28 29 30 31 32
[[4]]
[1] 34 35 36 37 38 39 40 41 42 43 44 45 46
我有一些非常大的数据框,我创建了一个条件列,它可以是 10、1、60 或 70,具体取决于某些特定值。介于两者之间的所有内容都是 0。然后我创建了一个小数据框,每隔 10 和 70 个位置(我想要的每个序列的开始和结束)并设法对我的数据框进行子集化,这样我只剩下每个 10 和 70 之间的内容(包括它们之间的 1、60 和 0)。
生成的数据框几乎是我需要的子集,条件列现在如下所示:
condition
10
0
0
1
0
0
0
60
0
0
70
10
0
0
1
0
60
0
0
70
0
0
10
0
0
1
0
0
60
0
0
70
0
10
0
0
1
0
0
0
0
60
0
0
0
70
每次70后,我应该再得到10,并重复每个循环。但是,当我在一夜之间对多个文件的循环设置此过程时,结果包含一些不需要的数据。正如您在上面看到的,70 到 10 之间有行。我想消除所有 70 到 10 之间的 0 行。在这个例子中,每个非零值之间只有几行,但我的实际数据远不止于此。
所以从上面得到的数据框将是:
condition
10
0
0
1
0
0
0
60
0
0
70
10
0
0
1
0
60
0
0
70
10
0
0
1
0
0
60
0
0
70
10
0
0
1
0
0
0
0
60
0
0
0
70
这些数据帧的范围从 1 到 1000 万行,因此我认为设置查看每一行并迭代的外观不会很有效。有什么想法吗?
UPDATE
我认为我有一个解决方案,使用的方法与我到达这里时所用的方法相同。
我试过了:
test$t = NA
test$t = ifelse(shift(test$ff== 70) & test$ff != 10, 1, test$t)
test$t = ifelse(shift(test$ff== 10, type = "lead") & test$ff != 70, 1, test$t)
test2 = data.frame(s = test$t[c(T,F)], e = test$t[c(F,T)])
Error in data.frame(s = test$t[c(T, F)], e = test$t[c(F, T)]) :
arguments imply differing number of rows: 44085, 44084
我的想法是找到每个 'bad' 70 之后和每个 'bad' 10 之前的行,然后删除使用 test2 之间的所有位置。它失败了,因为我的数据也有这样的情况:
70
0
0
60
0
0
70
10
这里没有配对 'bad' 10 代表 70。想一想,如果不是尝试删除坏的东西,而是使用我原来的方法再次子集,即仅从 10 - 70 中查找序列,我可能会解决它。我这样做的方式如下:
df2 = df[df$ff == 10 | df$ff == 70,]
test = data.frame(s = df2$datetime[c(T,F)], e = df2$datetime[c(F,T)])
for(i in 1:length(test$s)){test$ss[i] = which(df$datetime == test$s[i])}
for(i in 1:length(test$s)){test$ee[i] = which(df$datetime == test$e[i])}
for(i in 1:length(test$s)){df$t[test$ss[i]:test$ee[i]] = 1}
df_all= df[df$t ==1,]
高级吧?
zoo::na.locf
是你的朋友:
condition <- as.numeric(c("10", "0", "0", "1", "0", "0", "0", "60",
"0", "0", "70", "10", "0", "0", "1", "0", "60", "0", "0", "70",
"0", "0", "10"))
dfr <- data.frame(condition = condition)
dfr$between <- NA
dfr$between[dfr$condition == 70] <- TRUE
dfr$between[dfr$condition == 10] <- FALSE
dfr$between <- zoo::na.locf(dfr$between, na.rm = FALSE)
dfr$between[dfr$condition == 70] <- FALSE # don't remove the 70s themselves
dfr[! dfr$between, ]
假设您的条件 data.frame 称为 test
。
start_end<-data.frame(a=which(test$condition==10),b=which(test$condition==70))
得到一个 data.frame 标记每个开始和每个结束
获取生成序列的函数
fun.seq<-function(a,b){
return(seq(a,b,1))
}
将该函数应用于 start_end 的每一行并将其取消列出,select 行
test[unlist(mapply(fun.seq,start_end$a,start_end$b)),]
[1] 10 0 0 1 0 0 0 60 0 0 70 10 0 0 1 0 60 0 0 70 10 0 0 1 0 0 60 0 0 70 10 0 0 1 0 0 0 0 60 0 0 0 70
我不确定它在数百万行上是否足够快。
也许 data.table 可以更快地完成此操作,但我不确定该怎么做。
我想出了这个非常俗气的方法,简单但有效。
mapply 的输出:
mapply(fun.seq,start_end$a,start_end$b)
[[1]]
[1] 1 2 3 4 5 6 7 8 9 10 11
[[2]]
[1] 12 13 14 15 16 17 18 19 20
[[3]]
[1] 23 24 25 26 27 28 29 30 31 32
[[4]]
[1] 34 35 36 37 38 39 40 41 42 43 44 45 46