使用for循环在R中过滤数据帧

时间:2020-01-10 22:50:56

标签: r dataframe

我是R的新手,并且在使用更高级的过滤功能时遇到了困难。我有一个包含1500行家庭数据的数据框,需要过滤出至少有1个人年龄超过24岁的家庭成员。例如,在下面的示例集中,我只希望保留第3行,4和5。

PersonalID     DOB         HouseholdID
1            1961-04-15      123
2            2017-01-12      123
3            2000-01-02      122
4            2001-03-05      122
5            1996-08-22      122

最初,我只是过滤以与该年龄段的每个人都获取一个新的数据框,然后使用25岁以下人群的每个HouseholdID再次过滤一次(一次又一次,依此类推...),以检查是否有人否则,该HouseholdID超过24。

每当我一遍又一遍地做同样的事情时,似乎可能有一种使用函数的方法,但是我很难找到一个可行的函数。这是我目前的尝试,但我知道它有很多问题:

UNDER25df <- filter(df, DOB >= "yyyy-mm-dd")

for (UNDER25df$HouseholdID in df) {
    if (all(df$DOB >= "yyyy-mm-dd")) {
       view(filter(df, HouseholdID == "$HouseholdID"))
     }
 }

我得到的错误是:

“}”中意外的“}”

但是我很确定我可以将if语句嵌套在R中的for循环中,并且我对括号的位置非常小心,所以我不知道它到底指的是什么。

我不确定的是我是否可以以这种方式遍历数据帧,或者这是否有意义。我读过,矢量化通常对于高级过滤而言可能更好,但是尝试阅读有关它的文档,并且真的看不到如何解决这个问题。有人对我有任何建议或指示吗?

3 个答案:

答案 0 :(得分:1)

您不需要为此进行循环。试试

library(lubridate)
library(dplyr)

set.seed(1)
df <- tibble(DOB = Sys.Date() - sample(3000:12000, 6), 
             personalID = 1:6,
             HouseholdID = c(1,1,2,2,2,3))
df$DOB

# grab householdID from all persons that are at least 24
oldies <- df[(lubridate::today() - lubridate::ymd(df$DOB)) > years(24),
             "HouseholdID", TRUE]

# base R way
oldies <- df[as.Date(df$DOB) > as.Date("1993-2-10"),
             "HouseholdID", TRUE]

# household members in a household with someone 24 or older
df %>% 
  filter(HouseholdID %in% oldies)


# household members in a household with noone 24 or older
df %>% 
  filter(!(HouseholdID %in% oldies))

答案 1 :(得分:0)

我不确定您是否要选择所有人都在24岁以上或至少一个人在24岁以上的家庭。无论如何,您可以将subsetave

subset(df, ave(as.integer(format(Sys.Date(), "%Y")) - 
               as.integer(format(DOB, "%Y")) >= 24, HouseholdID, FUN = any))

这将选择至少一个人在24岁以上的家庭。如果要选择所有人在24岁以上的家庭,请使用all代替any中的FUN

类似地,使用dplyr,我们可以使用

library(dplyr)
df %>%
   group_by(HouseholdID) %>%
   filter(any(as.integer(format(Sys.Date(), "%Y")) - 
              as.integer(format(DOB, "%Y")) >= 24))

答案 2 :(得分:0)

我不确定您是否要按ID对行进行分组,以确保所有用户均小于或等于24岁。如果是这样,那么也许您可以尝试下面的代码

library(lubridate)
dfout <- subset(df, ave(floor(time_length(Sys.Date()-as.Date(DOB),"years"))<=24, HouseholdID, FUN = all))
  • 如果您真的想使用for循环来制作,那么下面是一个示例
dfout <- data.frame()
for (id in unique(df$HouseholdID)) {
  subdf <- subset(df,HouseholdID == id)
  if (with(subdf, all(floor(time_length(Sys.Date()-as.Date(DOB),"years"))<=24))) {
    dfout <- rbind(dfout,subdf)
  }
}

以上两种方法都可以将结果显示为

> dfout
  PersonalID        DOB HouseholdID
3          3 2000-01-02         122
4          4 2001-03-05         122
5          5 1996-08-22         122

数据

df <- structure(list(PersonalID = 1:5, DOB = c("1961-04-15", "2017-01-12", 
"2000-01-02", "2001-03-05", "1996-08-22"), HouseholdID = c(123L, 
123L, 122L, 122L, 122L)), class = "data.frame", row.names = c(NA, 
-5L))