How to take the first 5 lines in a group without replacing in another value of a variable

I am trying to understand how I can take only the first 5 lines of a group without replacing a different variable value. For example, if an existing data table (or frame) looks like this:

id V1
1 101
1 102
1 103
1 104
1 105
1 106
1 107
1 108
1 109
1 110
2 101
2 103
2 105
2 107
2 108
2 109
2 110
2 111
2 112
2 101
3 104
3 105
3 107
3 108
3 109
3 110
3 101
3 102
3 103
3 104

But I just want to get the first 5 rows for each group, but without replacing the V1 values ​​across the groups. So, the result table I want is ...:

id V1
1 101
1 102
1 103
1 104
1 105
2 107
2 108
2 109
2 110
2 111
3 NA

I try to do this using for loop, looking at each id every time .... taking the first 5 lines for each id and excluding the following lines with V1 values ​​in the previous identifiers. But since my data is really large (the number of identifiers exceeds a million), for the for loop you need to go through all the identifiers.

- , , ? !

+4
2

:

# create a vector to store set values
x <- numeric()
# compute the values by id and update x in the process
res <- lapply(split(df$V1, df$id), function(y) {
     y <- head(setdiff(y, x), 5)
     x <<- union(x, y)
     if(!length(y)) NA else y
})
# combine the result to data.frame
stack(res)
#   values ind
#1     101   1
#2     102   1
#3     103   1
#4     104   1
#5     105   1
#6     107   2
#7     108   2
#8     109   2
#9     110   2
#10    111   2
#11     NA   3
+4

- . , ( , id = 3 , ). . . , - ...

df = data.frame (id = c (1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,
      2,2,2,2,2,3,3,3,3,3,3,3,3,3,3),
V1 = c(101,102, 103,104,105,106,107,108,109,110,101,
103,105,107,108,109,110,111,112,101,104,
105,107,108,109,110,101,102,103,104))


df2 <- df
for (i in unique(df$id)) {
   dfsel <- data.frame(df2 %>% group_by(id) %>% filter(row_number() <= 5 & id == i))
   df3 <- df2[!(df2$V1 %in% dfsel$V1) & df2$id != i,]
   df2 <- rbind(dfsel,df3)
}
df2[with (df2, order(id)),]

id  V1
1 101
1 102
1 103
1 104
1 105
2 107
2 108
2 109
2 110
2 111

EDITED: . , , :) Performance, .

dd <- split(df$V1, df$id)
maxdf <- data.frame(mx = rep(0,length(dd)))

maxdf[1,1] <- dd[[1]][5]
dd[[1]][dd[[1]] > maxdf[1,1]] <- NA

n <- unique(df$id)[2:length(unique(df$id))]
for (i in n) {
  dd[[i]][dd[[i]] <= maxdf[i-1,1]] <- NA
  maxdf[i,1] <- dd[[i]][!is.na(dd[[i]])][5]
  dd[[i]][dd[[i]] > maxdf[i,1]] <- NA
}

df <- stack(dd)
names(df) <- c("V1","id")
df <- df[!is.na(df$V1),]

PS: :)

+1

Source: https://habr.com/ru/post/1675874/


All Articles