仅当条件满足时才从数据框中的每个组中选择行
pick rows from every group in data frame only when condition satisfies
我有一个包含两列的数据框。假设它已经按第一列分组。对于每个组,我只需要在第 2 列中的值为 100 时从该数据框中选取行。是否有最佳方法来执行此操作?
目前,我已经编写了一个如下的迭代解决方案,它基本上将每个组读入一个临时数据框,并在 column2 中的值为 100 时将行选入名为 finaldf 的最终数据框。
编辑:请注意 col2 中的数据不是按升序排列的,因此我不能使用诸如 mydf$col2 > 100 之类的条件。100 只是一个占位符,表示从何时开始我应该开始选择行。
myfun = function()
{
col1 = c(1,1,1,2,2,3,3,3,3,3)
col2 = c(80,100,75,90,100,75,100,12,14,150)
mydf = data.frame(col1,col2)
finaldf = NULL;
uniquecol1values = unique(col1)
for(i in 1:length(uniquecol1values))
{
tempdf = mydf[which(mydf$col1 == uniquecol1values[i]),]
print(tempdf)
startincluding = 0;
for(j in 1:nrow(tempdf))
{
if(tempdf[j,2] == 100)
{
startincluding = 1;
}
if(startincluding == 1)
{
finaldf = rbind(finaldf,tempdf[j,])
}
}
}
print(finaldf)
}
> mydf
col1 col2
1 1 80
2 1 100
3 1 75
4 2 90
5 2 100
6 3 75
7 3 100
8 3 12
9 3 14
10 3 150
> finaldf
col1 col2
2 1 100
3 1 75
5 2 100
7 3 100
8 3 12
9 3 14
10 3 150
编辑:如果我应用诸如 mydf[mydf$col2>=100,] 的条件,它只会给我 col2 值大于等于 100 的行。这不是正确的输出,因为我们想要尽管 75<100,但要包括像 (1, 75) 这样的行,因为我们已经看到第 1 组的值 100。
> mydf[mydf$col2>=100,]
col1 col2
2 1 100
5 2 100
7 3 100
10 3 150
您可以简单地使用:
# Split the data frame by col1
mydf.split <- split(mydf, mydf$col1)
# Apply to each group of elements (defined by col1)
# a function
res <- lapply(mydf.split, function(x)
{
# Find the position of the first element >= 100
pos=which(x$col2>=100)[[1]]
# Get all of the elements afterwards
x[pos:nrow(x),]
})
# Convert back to a df
res <- do.call("rbind", res)
bycol <- split(mydf,as.factor(mydf$col1))
newdf <- data.frame()
for (i in 1:length(bycol)) {
col <- bycol[[i]][2]
lcol <- col >= 100
start <- min(which(lcol == TRUE))
fin <- nrow(col)
newdf <- rbind(newdf, bycol[[i]][start:fin,])
}
这显示了 OP 最初要求的内容,即:
> newdf
col1 col2
2 1 100
3 1 75
5 2 100
7 3 100
8 3 12
9 3 14
10 3 150
这个算法的一个更紧凑的实现,使用@nico 的想法是:
bycol <- split(mydf,as.factor(mydf$col1))
temp <- lapply(bycol, function(x) {
col <- x[2]
lcol <- col >= 100
x[min(which(lcol == TRUE)) : nrow(col),]
})
newdf <- do.call("rbind", temp)
这可以通过 data.table
包轻松完成,无需任何 for
/lapply
循环
library(data.table)
setDT(mydf)[, .SD[which(match(col2, 100) == 1):.N], col1]
# col1 col2
# 1: 1 100
# 2: 1 75
# 3: 2 100
# 4: 3 100
# 5: 3 12
# 6: 3 14
# 7: 3 150
说明:
这个想法很简单,我们使用每组 match
来找到 100
的第一次出现(因为 match
函数总是 returns 第一次出现)然后我们简单地 select 比赛结束后所有数值向下,直到分组结束。
我有一个包含两列的数据框。假设它已经按第一列分组。对于每个组,我只需要在第 2 列中的值为 100 时从该数据框中选取行。是否有最佳方法来执行此操作?
目前,我已经编写了一个如下的迭代解决方案,它基本上将每个组读入一个临时数据框,并在 column2 中的值为 100 时将行选入名为 finaldf 的最终数据框。
编辑:请注意 col2 中的数据不是按升序排列的,因此我不能使用诸如 mydf$col2 > 100 之类的条件。100 只是一个占位符,表示从何时开始我应该开始选择行。
myfun = function()
{
col1 = c(1,1,1,2,2,3,3,3,3,3)
col2 = c(80,100,75,90,100,75,100,12,14,150)
mydf = data.frame(col1,col2)
finaldf = NULL;
uniquecol1values = unique(col1)
for(i in 1:length(uniquecol1values))
{
tempdf = mydf[which(mydf$col1 == uniquecol1values[i]),]
print(tempdf)
startincluding = 0;
for(j in 1:nrow(tempdf))
{
if(tempdf[j,2] == 100)
{
startincluding = 1;
}
if(startincluding == 1)
{
finaldf = rbind(finaldf,tempdf[j,])
}
}
}
print(finaldf)
}
> mydf
col1 col2
1 1 80
2 1 100
3 1 75
4 2 90
5 2 100
6 3 75
7 3 100
8 3 12
9 3 14
10 3 150
> finaldf
col1 col2
2 1 100
3 1 75
5 2 100
7 3 100
8 3 12
9 3 14
10 3 150
编辑:如果我应用诸如 mydf[mydf$col2>=100,] 的条件,它只会给我 col2 值大于等于 100 的行。这不是正确的输出,因为我们想要尽管 75<100,但要包括像 (1, 75) 这样的行,因为我们已经看到第 1 组的值 100。
> mydf[mydf$col2>=100,]
col1 col2
2 1 100
5 2 100
7 3 100
10 3 150
您可以简单地使用:
# Split the data frame by col1
mydf.split <- split(mydf, mydf$col1)
# Apply to each group of elements (defined by col1)
# a function
res <- lapply(mydf.split, function(x)
{
# Find the position of the first element >= 100
pos=which(x$col2>=100)[[1]]
# Get all of the elements afterwards
x[pos:nrow(x),]
})
# Convert back to a df
res <- do.call("rbind", res)
bycol <- split(mydf,as.factor(mydf$col1))
newdf <- data.frame()
for (i in 1:length(bycol)) {
col <- bycol[[i]][2]
lcol <- col >= 100
start <- min(which(lcol == TRUE))
fin <- nrow(col)
newdf <- rbind(newdf, bycol[[i]][start:fin,])
}
这显示了 OP 最初要求的内容,即:
> newdf
col1 col2
2 1 100
3 1 75
5 2 100
7 3 100
8 3 12
9 3 14
10 3 150
这个算法的一个更紧凑的实现,使用@nico 的想法是:
bycol <- split(mydf,as.factor(mydf$col1))
temp <- lapply(bycol, function(x) {
col <- x[2]
lcol <- col >= 100
x[min(which(lcol == TRUE)) : nrow(col),]
})
newdf <- do.call("rbind", temp)
这可以通过 data.table
包轻松完成,无需任何 for
/lapply
循环
library(data.table)
setDT(mydf)[, .SD[which(match(col2, 100) == 1):.N], col1]
# col1 col2
# 1: 1 100
# 2: 1 75
# 3: 2 100
# 4: 3 100
# 5: 3 12
# 6: 3 14
# 7: 3 150
说明:
这个想法很简单,我们使用每组 match
来找到 100
的第一次出现(因为 match
函数总是 returns 第一次出现)然后我们简单地 select 比赛结束后所有数值向下,直到分组结束。