动态确定数据框列是否存在,如果存在,则进行突变

时间:2018-10-25 21:38:04

标签: r dplyr

我有一些代码可以根据客户端名称从数据库中提取和处理数据。某些客户端可能具有不包含特定列名的数据,例如last_namefirst_name。对于不使用last_namefirst_name的客户,我不在乎。对于使用使用这两个字段之一的客户,我需要使用mutate() toupper()将这些列if()使用,以便稍后在ETL过程中加入这些标准化字段。

现在,我正在使用一系列library(dplyr) set.seed(256) b <- data.frame(id = sample(1:100, 5, FALSE), col_name = sample(1000:9999, 5, FALSE), another_col = sample(1000:9999, 5, FALSE)) d <- data.frame(id = sample(1:100, 5, FALSE), col_name = sample(1000:9999, 5, FALSE), last_name = sample(letters, 5, FALSE)) mutate_first_last <- function(df){ mutate_first_name <- function(df){ df %>% mutate(first_name = first_name %>% toupper()) } mutate_last_name <- function(df){ df %>% mutate(last_name = last_name %>% toupper()) } n <- c("first_name", "last_name") %in% names(df) if (n[1] & n[2]) return(df %>% mutate_first_name() %>% mutate_last_name()) if (n[1] & !n[2]) return(df %>% mutate_first_name()) if (!n[1] & n[2]) return(df %>% mutate_last_name()) if (!n[1] & !n[2]) return(df) } 语句和一些辅助函数来查找数据框的名称,然后对它们的名称进行更改(如果存在)。 I'm using if() statements because ifelse() is mostly vectorized and doesn't handle dataframes well.

> b %>% mutate_first_last()
  id col_name another_col
1 48     8318        6207
2 39     7155        7170
3 16     4486        4321
4 55     2521        8024
5 15     1412        4875
> d %>% mutate_first_last()
  id col_name last_name
1 64     7438         A
2 43     4551         Q
3 48     7401         K
4 78     3682         Z
5 87     2554         J

我能达到我期望的方式

if()

但这是处理此类任务的最佳方法吗?动态查看是否在数据框中存在列名,然后将其更改(如果存在)?在此函数中必须具有多个$.each($(".product-comment"), function (key, value) { var showmoreHtml = $(this).html(); var showlessHtml = showmoreHtml.substr(0, 400); if (showmoreHtml.length > 400) { $(this).html(showlessHtml).append("<a href='' class='product-comment-more'> (...Show More)</a>"); } $(this).on("click", ".product-comment-more", function (event) { event.preventDefault(); $(this).parent(".product-comment").html(showmoreHtml).append("<a href='' class='product-comment-less'> (Show less)</a>"); }); $.ajax({ method: 'POST', url: urlCreateReview, data: form_data, cache: false, processData: false, contentType: false, success: function(data) { $(".tab-comment-holder").load(" .tab-comment-holder"); }, 语句似乎很奇怪。 是否有更简化的方式来处理这些数据?

2 个答案:

答案 0 :(得分:4)

您可以将mutate_at中的one_ofdplyr一起使用。仅当它与c("first_name", "last_name")之一匹配时,此列才会突变。如果不匹配,它将生成一个简单的警告,但是您可以忽略或禁止它。

library(dplyr)

d %>%
  mutate_at(vars(one_of(c("first_name", "last_name")), toupper)

  id col_name last_name
1 19     7461         V
2 52     9651         H
3 56     1901         P
4 13     7866         Z
5 25     9527         U

# example with no match
b %>%
  mutate_at(vars(one_of(c("first_name", "last_name"))), toupper)

  id col_name another_col
1 34     9315        8686
2 26     5598        4124
3 17     3318        2182
4 32     1418        4369
5 49     4759        6680
Warning message:
Unknown variables: `first_name`, `last_name`

?select_helpers中还有一堆其他dplyr-

  

这些函数使您可以根据变量的名称选择变量。

     

starts_with():以前缀开头

     

ends_with():以前缀结尾

     

contains():包含文字字符串

     

matches():匹配正则表达式

     

num_range():一个数字范围,例如x01,x02,x03。

     

one_of():字符向量中的变量。

     

everything():所有变量。

答案 1 :(得分:1)

更新 dplyr 1.0.0

dplyr 1.0 中,_at_all 等 mutate 的作用域变体被 across() 替换。

此外,对于这种情况,最好的 tidy_select 助手是 any_of,因为它将对存在的变量执行,但忽略那些不存在的变量(没有警告消息)。

因此,您可以编写以下内容:

# purrr syntax
d %>% mutate(across(any_of(c("first_name", "last_name")), ~toupper(.x)))

# function name syntax
d %>% mutate(across(any_of(c("first_name", "last_name")), toupper))

两者都返回变异的列

  id col_name last_name
1 19     4398         Q
2 72     1135         S
3 54     9767         V
4 60     4364         K
5 35     1564         X

同时

b %>% mutate(across(any_of(c("first_name", "last_name")), toupper))

忽略列并因此返回(没有警告消息):

  id col_name another_col
1 42     7601        4482
2 22     1773        7072
3 47     2719        5884
4  1     9595        5945
5 81     8044        3927