如何将变异的列重新定位到原始列旁边?

How can I relocate mutated columns next to the original colums?

我创建了一个函数,该函数跨列变异并从每个列创建新的命名列。新列放在数据框的右侧,而我想让它们与每个原始列相邻。我正在寻找一种解决方案,该解决方案可以推广到可能使用此函数的任何数据框,编写 select 语句来重新排序列对于我的用例来说不够自动。

test_data <- data.frame(data_col_1 = c(1,2,3),
                        data_col_2 = c(1,2,3),
                        data_col_3 = c(1,2,3),
                        another_column = c("a","b","c"))


perc_funct <- function(df, columns, numerator){
  
p_f <- function(x, numerator){
  
  (x/numerator)*100
}
    j <- df %>%
     mutate( across({{columns}}, 
                    .fns = list(perc = ~p_f(.x, numerator)),
                    .names = "{col}_{fn}"))# need to figure out a way to get the columns ordered 
return(j)
}

test_data %>% perc_funct(columns = starts_with("data"), numerator = 1)

输出当前将所有新列放在右侧。

"data_col_1" "data_col_2" "data_col_3" "another_column" "data_col_1_perc" "data_col_2_perc" " data_col_3_perc

我想要的输出将每个新列放在每个旧列的右侧。 "data_col_1" "data_col_1_perc" "data_col_2" "data_col_2_perc" "data_col_3" "data_col_3_perc" "another_column

之后我通常使用 select(sort(names(.))) 对列进行排序:

library(dplyr)

test_data %>% 
  perc_funct(columns = starts_with("data"), numerator = 1) %>% 
  select(sort(names(.)))

#>   data_col_1 data_col_1_perc data_col_2 data_col_2_perc data_col_3
#> 1          1             100          1             100          1
#> 2          2             200          2             200          2
#> 3          3             300          3             300          3
#>   data_col_3_perc
#> 1             100
#> 2             200
#> 3             300

reprex package (v2.0.1)

于 2022-04-01 创建

如果我想在同一位置保留其他列怎么办?

这只是将我的解决方案与其他 select 语句或 dplyr 动词嵌套在一起的问题。作为中间步骤,您可能必须保存包含未排序列的数据框。

示例 1

这是一个包含其他三列的示例,其中一些列在前面,一些列在最后,其他列在任何地方但都放在一起。

library(dplyr)

df <- 
  test_data %>% 
  mutate(first_col = 1, other_columns = 100, last_col = 999) %>%
  perc_funct(columns = starts_with("data"), numerator = 1)

# Unsorted:
df %>% names()
#> [1] "data_col_1"      "data_col_2"      "data_col_3"      "first_col"      
#> [5] "other_columns"   "last_col"        "data_col_1_perc" "data_col_2_perc"
#> [9] "data_col_3_perc"

# Sorted:
df %>% 
  select(
    first_col,
    df %>% select(starts_with("data")) %>% names() %>% sort(), 
    everything(),
    last_col
  ) 
#>   first_col data_col_1 data_col_1_perc data_col_2 data_col_2_perc data_col_3
#> 1         1          1             100          1             100          1
#> 2         1          2             200          2             200          2
#> 3         1          3             300          3             300          3
#>   data_col_3_perc other_columns last_col
#> 1             100           100      999
#> 2             200           100      999
#> 3             300           100      999

reprex package (v2.0.1)

于 2022-04-01 创建
示例 2

还有一个替代方案使用 col_bind():

如果您只想将新列放在最后,但与创建它们的列一起排序,您还可以执行以下操作:

library(dplyr)
df %>% 
  select(
    -starts_with("data")
  ) %>% bind_cols(
    df %>% 
      select(
        df %>% select(starts_with("data")) %>% names() %>% sort()
      )
  )
#>   first_col other_columns last_col data_col_1 data_col_1_perc data_col_2
#> 1         1           100      999          1             100          1
#> 2         1           100      999          2             200          2
#> 3         1           100      999          3             300          3
#>   data_col_2_perc data_col_3 data_col_3_perc
#> 1             100          1             100
#> 2             200          2             200
#> 3             300          3             300

使用 dplyr(自版本 1.0.0 起)移动列的推荐方法是使用 relocate()relocate() 支持 tidyselect 语义,但重要的是仅对选定的列起作用,而将所有其他列留在原地。在您的情况下,您可以在以 data.

开头的列上 grep()sort()
test_data <- data.frame(column_1 = 1:3,
                        data_col_1 = c(1,2,3),
                        data_col_2 = c(1,2,3),
                        data_col_3 = c(1,2,3),
                        another_column = c("a","b","c"))


test_data %>%
  perc_funct(columns = starts_with("data"), numerator = 1) %>%
  relocate(sort(grep("^data", names(.), value = TRUE)), .before = data_col_1)

  column_1 data_col_1 data_col_1_perc data_col_2 data_col_2_perc data_col_3 data_col_3_perc another_column
1        1          1             100          1             100          1             100              a
2        2          2             200          2             200          2             200              b
3        3          3             300          3             300          3             300              c

.before(或.after)参数指定重定位列的位置,在这种情况下,您可以将它们放在 data_col_1.

之前

另一种可能性是使用 contains() 和原始数据帧中的列顺序

test_data <- data.frame(column_1 = 1:3,
                        data_col_1 = c(1,2,3),
                        data_col_2 = c(1,2,3),
                        data_col_3 = c(1,2,3),
                        another_column = c("a","b","c"))


test_data %>% perc_funct(columns = starts_with("data"), numerator = 1) %>% 
  select(contains(test_data %>% colnames()))