R 基于函数参数创建一系列具有名称的变量

R 基于函数参数创建一系列具有名称的变量,r,dplyr,mutate,R,Dplyr,Mutate,我有一系列值为1.2、2.5等的变量。我想按小数点分隔数字,以便为整数和小数点创建一个新列,然后分配总分 HT_Q1 <- c(1.2, 2.5, 7.4) HT_Q2 <- c(2.5, 8.5, 9.5) AT_Q1 <- c(2.4, 1.2, 1.4) AT_Q2 <- c(6.5, 1.5, 9.10) df <- data.frame(HT_Q1, HT_Q2, AT_Q1, AT_Q2) 但是,我想编写一个函数,这样就不必为每个变量重复上面的代码。是

我有一系列值为1.2、2.5等的变量。我想按小数点分隔数字,以便为整数和小数点创建一个新列,然后分配总分

HT_Q1 <- c(1.2, 2.5, 7.4)
HT_Q2 <- c(2.5, 8.5, 9.5)
AT_Q1 <- c(2.4, 1.2, 1.4)
AT_Q2 <- c(6.5, 1.5, 9.10)
df <- data.frame(HT_Q1, HT_Q2, AT_Q1, AT_Q2)
但是,我想编写一个函数,这样就不必为每个变量重复上面的代码。是否可以将每个变量(HT_Q1、HT_Q2等)作为参数传递给函数,并创建相应的变量(例如HT_Q2_g、HT_Q2_B、AT_Q2_g等)

我尝试根据传递给函数的参数创建变量名,但无效:

edit_score <- function(var){
  mutate(df,
         paste0(var, "_G") = trunc(var),
         paste0(var, "_B") = var %% 1 * 10,
         paste0(var, "_P") = (paste0(var, "_G") * 6) + paste0(var, "_B"))
}

edit_score(HT_Q1)
edit_score(HT_Q2)
edit_score(AT_Q1)
edit_score(AT_Q2)

edit_score您可以在此处使用非标准评估:

library(dplyr)
library(purrr)
library(rlang)

edit_score <- function(var){
  transmute(df,
         !!paste0(var, "_G") := trunc(!!sym(var)),
         !!paste0(var, "_B") := !!sym(var) %% 1 * 10,
         !!paste0(var, "_P") := !!sym(paste0(var, "_G")) * 6 + 
                                !!sym(paste0(var, "_B")))
}

bind_cols(df, map_dfc(names(df), edit_score))

使用tidyverse时,数据的格式要整齐、长,这一点很重要。这使得使用tidyverse函数更容易。使用gather函数,我们可以将数据转换为长格式,mutate将对所有值应用函数

HT_Q1 <- c(1.2, 2.5, 7.4)
HT_Q2 <- c(2.5, 8.5, 9.5)
AT_Q1 <- c(2.4, 1.2, 1.4)
AT_Q2 <- c(6.5, 1.5, 9.10)
df <- data.frame(HT_Q1, HT_Q2, AT_Q1, AT_Q2)

df <- df %>%
  gather() %>%
  mutate(G = trunc(value), 
         B = value %% 1 * 10,
         P = G*6 + B)

#     key value G B  P
#1  HT_Q1   1.2 1 2  8
#2  HT_Q1   2.5 2 5 17
#3  HT_Q1   7.4 7 4 46
#4  HT_Q2   2.5 2 5 17
#5  HT_Q2   8.5 8 5 53
#6  HT_Q2   9.5 9 5 59
#7  AT_Q1   2.4 2 4 16
#8  AT_Q1   1.2 1 2  8
#9  AT_Q1   1.4 1 4 10
#10 AT_Q2   6.5 6 5 41
#11 AT_Q2   1.5 1 5 11
#12 AT_Q2   9.1 9 1 55
HT\u Q1您可以使用
cross()
lst()
功能,该功能引用了先前创建的组件

library(dplyr)

df %>%
  mutate(across(.fns = lst( G = function(x) trunc(x),
                            B = function(x) x %% 1 * 10,
                            P = ~ (G(.) * 6) + B(.) )))
输出

cross()
自动创建新的列名,并根据需要用
“\uu”
分隔。您还可以通过
.names
参数自定义新的名称模式

#   HT_Q1 HT_Q2 AT_Q1 AT_Q2 HT_Q1_G HT_Q1_B HT_Q1_P
# 1   1.2   2.5   2.4   6.5       1       2       8
# 2   2.5   8.5   1.2   1.5       2       5      17
# 3   7.4   9.5   1.4   9.1       7       4      46
# 
#   HT_Q2_G HT_Q2_B HT_Q2_P AT_Q1_G AT_Q1_B AT_Q1_P
# 1       2       5      17       2       4      16
# 2       8       5      53       1       2       8
# 3       9       5      59       1       4      10
# 
#   AT_Q2_G AT_Q2_B AT_Q2_P
# 1       6       5      41
# 2       1       5      11
# 3       9       1      55
仅使用基本R
#类似python的字符串串联`+`

`%+%`谢谢,BaseR方法更容易理解!
df <- df %>%
  pivot_wider(id_cols = key, names_from = key, values_from = value:P, values_fn=list, , names_glue = "{key}_{.value}") %>%
  unnest(cols=everything())
colnames(df) = gsub("_value", "", colnames(df))

#  HT_Q1 HT_Q2 AT_Q1 AT_Q2 HT_Q1_G HT_Q2_G AT_Q1_G AT_Q2_G HT_Q1_B HT_Q2_B AT_Q1_B AT_Q2_B HT_Q1_P HT_Q2_P AT_Q1_P AT_Q2_P
#1   1.2   2.5   2.4   6.5       1       2       2       6       2       5       4       5       8      17      16      41
#2   2.5   8.5   1.2   1.5       2       8       1       1       5       5       2       5      17      53       8      11
#3   7.4   9.5   1.4   9.1       7       9       1       9       4       5       4       1      46      59      10      55
library(dplyr)

df %>%
  mutate(across(.fns = lst( G = function(x) trunc(x),
                            B = function(x) x %% 1 * 10,
                            P = ~ (G(.) * 6) + B(.) )))
#   HT_Q1 HT_Q2 AT_Q1 AT_Q2 HT_Q1_G HT_Q1_B HT_Q1_P
# 1   1.2   2.5   2.4   6.5       1       2       8
# 2   2.5   8.5   1.2   1.5       2       5      17
# 3   7.4   9.5   1.4   9.1       7       4      46
# 
#   HT_Q2_G HT_Q2_B HT_Q2_P AT_Q1_G AT_Q1_B AT_Q1_P
# 1       2       5      17       2       4      16
# 2       8       5      53       1       2       8
# 3       9       5      59       1       4      10
# 
#   AT_Q2_G AT_Q2_B AT_Q2_P
# 1       6       5      41
# 2       1       5      11
# 3       9       1      55
# python-like string concatenation `+`
`%+%` <- function(str1, str2) { 
  paste0(str1, str2)
}

add_columns <- function(df, col) {
  df[, col %+% "_G"] <- trunc(df[, col])
  df[, col %+% "_B"] <- df[, col] %% 1 * 10
  df[, col %+% "_P"] <- df[,  col %+% "_G"] * 6 + df[, col %+% "_B"]
  df
}

generate_GBP_columns <- function(df) {
  for (col in names(df)) {
    df <- add_columns(df, col)
  }
  df
}

generate_GBP_columns(df)


#   HT_Q1 HT_Q2 AT_Q1 AT_Q2 HT_Q1_G HT_Q1_B HT_Q1_P HT_Q2_G HT_Q2_B HT_Q2_P
# 1   1.2   2.5   2.4   6.5       1       2       8       2       5      17
# 2   2.5   8.5   1.2   1.5       2       5      17       8       5      53
# 3   7.4   9.5   1.4   9.1       7       4      46       9       5      59
#   AT_Q1_G AT_Q1_B AT_Q1_P AT_Q2_G AT_Q2_B AT_Q2_P
# 1       2       4      16       6       5      41
# 2       1       2       8       1       5      11
# 3       1       4      10       9       1      55