【问题标题】:Filter a dataframe by passing "type" as input to columns in R通过将“类型”作为输入传递给 R 中的列来过滤数据框
【发布时间】:2021-10-07 02:21:41
【问题描述】:

我有一个这样的数据框

    id <- c(5738180,51845,167774,517814,1344920,517833,51844)
    measurement <- c("Length","Breadth","Breadth","Length","Length","Length","Breadth")
    map_flag <- c(0,1,1,0,0,0,0)
    cap_flag <- c(1,0,0,1,1,0,0)
    df.sample <- data.frame(id,measurement,map_flag,cap_flag) 
    

df.sample

       id measurement map_flag cap_flag
  5738180      Length        0        1
    51845     Breadth        1        0
   167774     Breadth        1        0
   517814      Length        0        1
  1344920      Length        0        1
   517833      Length        0        0
    51844     Breadth        0        0

我正在尝试创建一个函数,该函数将dftype 作为输入并根据过滤后的type 返回df

如果我进来

  • type = "map",它应该使用map_flag = 1 列过滤df并返回一个df
  • type = "cap",它应该使用cap_flag = 1 列过滤df并返回一个df
  • type = "Length",它应该使用measurement = Length 列过滤df并返回一个df

期望的输出

type = "地图"

       id measurement map_flag cap_flag
    51845     Breadth        1        0
   167774     Breadth        1        0

type = "cap"

    id measurement map_flag cap_flag
  5738180      Length        0        1
   517814      Length        0        1
  1344920      Length        0        1

type = "长度"

       id measurement map_flag cap_flag
  5738180      Length        0        1
   517814      Length        0        1
  1344920      Length        0        1
   517833      Length        0        0

我正在尝试这样做,但没有得到我想要的

 testFun <- function (df, type) {
      df <- df %>%
        {if (type==starts_with(map) filter(map_flag==1) }
      return(df)
    }

如果有人能指出我正确的方向,我将不胜感激。

【问题讨论】:

  • 逻辑我不清楚。对于type == 'map',它选择相应的列(map_flag)并过滤值= 1的行。type == 'cap'也是如此,但type = 'Length'不遵循该逻辑。你确定它必须包含在同一个函数中吗?
  • @RonakShah 我明白你的意思,但我正在使用的逻辑是故意这样设置的。 2 列是标志,1 列是非标志。
  • 那么你想怎么实现这个功能呢?你怎么知道哪些输入是标志,哪些是非标志。如果只有 3 个输入,您要对过滤器进行硬编码吗?就像@Park 的回答一样?
  • @RonakShah 是的,Park 的回答效果很好,但我想看看我们是否可以通过不对过滤器进行硬编码来做到这一点。我会欢迎你的建议。

标签: r dplyr tidyverse


【解决方案1】:

你可以试试

func <- function(df, type = c("map", "cap", "Length")){
  if (type == "map"){
    df %>% filter(map_flag == 1)
  } else if (type == "cap") {
    df %>% filter(cap_flag == 1)
  } else if (type == "Length") {
    df %>% filter(measurement == "Length")
  } else {
    stop("select type amont map, cap, and Length")
  }
  
  
  
}

func(df.sample, "map")
      id measurement map_flag cap_flag
1  51845     Breadth        1        0
2 167774     Breadth        1        0
func(df.sample, "cap")
1 5738180      Length        0        1
2  517814      Length        0        1
3 1344920      Length        0        1
func(df.sample, "Length")
1 5738180      Length        0        1
2  517814      Length        0        1
3 1344920      Length        0        1
4  517833      Length        0        0

错误信息是这样的

func(df.sample, "ma")
Error in func(df.sample, "ma") : select type amont map, cap, and Length

新的

func <- function(df, type = c("map", "cap", "Length")){
  key <- paste0(type, "_flag")
  res1 <- try(df %>% filter(!!as.symbol(key) ==1), silent = TRUE)
  res2 <- df %>% filter(measurement == "Length")
  if(is(res1, "try-error")) res2 else res1

  
}

【讨论】:

  • 非常感谢。这非常接近我想要的,但是有没有一种方法可以通过不在函数中对过滤器值进行硬编码来做到这一点?
  • @Sharath 我试试看。
  • @Sharath 我在上面添加了一个新代码。
【解决方案2】:

如果只有 3 个可能的 type 输入,我建议使用 @Park 的答案,因为它很容易理解并且可以满足要求。

我提供了另一个选项,您不需要列出每个输入的条件。它检查数据中是否存在type_flag 列,并根据该条件返回输出。

library(dplyr)

testFun <- function (df, type) {
  col <- paste0(type, '_flag')
  if(col %in% colnames(df)) {
    res <- df %>% filter(.data[[col]] == 1)
  } else {
    res <- df %>% filter(measurement == type)
  }
  return(res)
}

testFun(df.sample, "map")
#      id measurement map_flag cap_flag
#1  51845     Breadth        1        0
#2 167774     Breadth        1        0

testFun(df.sample, "cap")
#       id measurement map_flag cap_flag
#1 5738180      Length        0        1
#2  517814      Length        0        1
#3 1344920      Length        0        1

testFun(df.sample, "Length")
#       id measurement map_flag cap_flag
#1 5738180      Length        0        1
#2  517814      Length        0        1
#3 1344920      Length        0        1
#4  517833      Length        0        0

【讨论】:

  • 这太棒了。多谢。我同意你对朴的回答。这很容易理解。我会根据我的需要使用你的任何一个答案。
【解决方案3】:

这个解决方案只需要基础 R 并且可以使用 data.framedata.table 输入:

testFun <- function(df, type) {
    
    key <- sprintf('%s_flag', type)

    if(key %in% names(df)) {
        return(df[df[[key]] == 1,])
    } else {
        # For other `type`s fall back to this - I think this is bad!
        return(df[df$measurement == 'Length',])    
    }

}

但是,从设计的角度来看,我更喜欢这个:

testFun <- function(df, type) {
    if(type == 'map') {
        return(df[df$map_flag == 1,])
    }
    if(type == 'cap') {
        return(df[df$cap_flag == 1,])
    }
    if(type == 'Length') {
        return(df[df$measurement == 'Length',])
    }
    stop(sprintf('Invald type: %s', type))
}

或要求type 是输入data.frame 中的一列。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-03-24
    • 1970-01-01
    • 1970-01-01
    • 2016-10-13
    • 1970-01-01
    • 1970-01-01
    • 2011-02-22
    • 1970-01-01
    相关资源
    最近更新 更多