df
是一个数据帧,其中每一行都是一对项(来自item1
和item2
(。
我想保留数据帧的第一行,然后只保留item2
的前一个值是item1
的当前值的第一行。所以我把我的数据改为output
。
我更喜欢tidy
(或purrr
(的方式,但愿意接受任何建议。
df <- structure(list(item1 = c(1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L,
2L, 3L, 3L, 3L, 3L, 3L, 4L, 4L, 4L, 4L, 5L, 5L, 6L, 6L, 7L),
item2 = c(4L, 5L, 6L, 7L, 8L, 4L, 5L, 6L, 7L, 8L, 4L, 5L,
6L, 7L, 8L, 5L, 6L, 7L, 8L, 7L, 8L, 7L, 8L, 8L)), row.names = c(NA,
-24L), class = c("tbl_df", "tbl", "data.frame"))
df
#> item1 item2
#> 1 1 4
#> 2 1 5
#> 3 1 6
#> 4 1 7
#> 5 1 8
#> 6 2 4
#> 7 2 5
#> 8 2 6
#> 9 2 7
#> 10 2 8
#> 11 3 4
#> 12 3 5
#> 13 3 6
#> 14 3 7
#> 15 3 8
#> 16 4 5
#> 17 4 6
#> 18 4 7
#> 19 4 8
#> 20 5 7
#> 21 5 8
#> 22 6 7
#> 23 6 8
#> 24 7 8
output <- data.frame(item1 = c(1,4,5,7),
item2 = c(4,5,7,8))
output
#> item1 item2
#> 1 1 4
#> 2 4 5
#> 3 5 7
#> 4 7 8
创建于2022-09-22由reprex包(v2.0.1(
这里有一个使用tidyverse的解决方案。
使用lag(..., default = 1)
确保我们也输出第一行。
library(tidyverse)
df <- tibble(
item1 = c(1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 3L, 3L, 3L, 3L, 3L, 4L, 4L, 4L, 4L, 5L, 5L, 6L, 6L, 7L),
item2 = c(4L, 5L, 6L, 7L, 8L, 4L, 5L, 6L, 7L, 8L, 4L, 5L, 6L, 7L, 8L, 5L, 6L, 7L, 8L, 7L, 8L, 7L, 8L, 8L)
)
df %>%
group_by(item1) %>%
summarize(item2 = first(item2)) %>%
filter(item1 == lag(item2, default = 1))
#> # A tibble: 4 × 2
#> item1 item2
#> <int> <int>
#> 1 1 4
#> 2 4 5
#> 3 5 7
#> 4 7 8
创建于2022-09-22由reprex包(v2.0.1(
这可能不是您想要的(不是一个非常整洁的解决方案(,但它提供了所需的输出。
library(tidyverse)
df <- data.frame(
item1 = c(1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L,
2L, 3L, 3L, 3L, 3L, 3L, 4L, 4L, 4L, 4L, 5L, 5L, 6L, 6L, 7L),
item2 = c(4L, 5L, 6L, 7L, 8L, 4L, 5L, 6L, 7L, 8L, 4L, 5L,
6L, 7L, 8L, 5L, 6L, 7L, 8L, 7L, 8L, 7L, 8L, 8L)
)
my_filter <- function(df_to_find, df_orig){
value_to_find <- tail(df_to_find, 1)$item2
df_found <- df_orig %>%
filter(item1 == value_to_find) %>%
head(1)
if(nrow(df_found) > 0){
# if something found, recall this function
# with the newly found data appended to the old results
return(Recall(bind_rows(df_to_find, df_found), df_orig))
} else{
# once you reach a state when nothing else is found return the results so far
# this is called recursion in programming
return(bind_rows(df_to_find))
}
}
创建于2022-09-22由reprex包(v2.0.1(
这里有另一个不规则和递归解决方案:
last2current = function (x) {
first = x[1, ]
first_match = with(x, match(item2[1], item1))
if (is.na(first_match)) return(first)
other = x[first_match:nrow(x), ]
rbind(first, last2current(other))
}
last2current(df)
item1 item2
1 1 4
16 4 5
20 5 7
24 7 8
说明:
这是一个递归函数,这意味着它调用自己。它存储第一行,然后在item1
上查找item2[1]
的第一个匹配,并将行号存储在first_match
中。如果没有first_match
,就意味着我们完了,所以return()
。如果存在匹配,则它对从第一个匹配到数据帧结束的行执行相同的过程。最后它cbind
是所有的行。
注意,如果存在item1 == item2
的行,则这将失败,因为item1[1]
包括在match
中。
这不会直接向量化——我会用一个简单的for循环来实现。这几乎肯定会比任何大规模数据的递归解决方案更快。
keep = logical(length = nrow(df))
keep[1] = TRUE
target = df$item2[1]
for(i in 2:nrow(df)) {
if(df$item1[i] == target) {
keep[i] = TRUE
target = df$item2[i]
}
}
result = df[keep, ]
result
# # A tibble: 4 × 2
# item1 item2
# <int> <int>
# 1 1 4
# 2 4 5
# 3 5 7
# 4 7 8
基R递归:
relation <- function(df, row){
if(is.na(row)) head(row, -1)
else c(row, relation(df, match(df[row, 2], df[,1])))
}
# Starting at row 1
df[relation(df, 1), ]
item1 item2
1 1 4
16 4 5
20 5 7
24 7 8
# Starting at row 2
df[relation(df, 2), ]
item1 item2
2 1 5
20 5 7
24 7 8
# Starting at row 4
df[relation(df, 4), ]
item1 item2
4 1 7
24 7 8