繁体   English   中英

如何使用purrr:map函数使用动态变量更改多列?

[英]How to mutate multiple columns with dynamic variable using purrr:map function?

我有一个数据框如下:

df <- data.frame(
  id  = c(1:5),
  a   = c(3,10,4,0,15),
  b   = c(2,1,1,0,3),
  c   = c(12,3,0,3,1),
  d   = c(9,7,8,0,0),
  e   = c(1,2,0,2,2)
  )

我需要添加多列,其名称由a:c3:5组合给出。 3:5也用于sum函数:

df %>% mutate(
  usa_3 = sum(1+3),
  usa_4 = sum(1+4),
  usa_5 = sum(1+5),
  canada_3 = sum(1+3),
  canada_4 = sum(1+4),
  canada_5 = sum(1+5),
  nz_3 = sum(1+3),
  nz_4 = sum(1+4),
  nz_5 = sum(1+5)
  )

结果真的很简单,但我不想重复输入类似的代码。

  id  a b  c d e usa_3 usa_4 usa_5 canada_3 canada_4 canada_5 nz_3 nz_4 nz_5
1  1  3 2 12 9 1     4     5     6        4        5        6    4    5    6
2  2 10 1  3 7 2     4     5     6        4        5        6    4    5    6
3  3  4 1  0 8 0     4     5     6        4        5        6    4    5    6
4  4  0 0  3 0 2     4     5     6        4        5        6    4    5    6
5  5 15 3  1 0 2     4     5     6        4        5        6    4    5    6

变量为字母前缀,整数范围为后缀。 Postfix也与sum函数有关1+postfix 在这种情况下,它们每个都有3个值,因此结果有9个附加列。

我不喜欢定义了一堆代码,并假设之外的功能map在functino purrr可以帮助它。

你知道如何使它工作吗? 尤其是很难在管道中提供动态列名称。

我发现了一些类似的问题,但与我的需求不符。

多元变异
如何通过purrr和dplyr :: mutate使用映射来基于列对创建多个新列

=====其他信息=====
让我澄清一下此问题的一些条件。 实际上, sum(1+3)sum(1+4) ...部分由as.factor(cutree(X,k=X))代替,其中X是聚类分析的重用,而Y是定义为3:5的变量3:5在示例中为3:5 cutree()是一个函数,用于定义我们在哪个部分中切割存储在聚类分析结果中的树状图。

至于列名usa_3, usa_4 ... nz_5 ,国家名称被聚类分析方法(例如ward,McQuitty,Median方法等)(七个方法)代替,整数3、4、5是定义我需要按照哪一部分切割树状图。

作为用于X在函数as.factor(cutree(X,k=X))聚类分析的结果也有其对应于每个方法的几个数据帧。 我意识到另一个问题是如何将功能应用于每个数据框(存储在不同数据框中的聚类分析结果)。
我当前正在使用的实际脚本是这样的:

cluste_number <- original_df %>% mutate(
    ## Ward
    ward_3=as.factor(cutree(clst.ward,k=3)),
    ward_4=as.factor(cutree(clst.ward,k=4)),
    ward_5=as.factor(cutree(clst.ward,k=5)),
    ward_6=as.factor(cutree(clst.ward,k=6)),
    ## Single
    sing_3=as.factor(cutree(clst.sing,k=3)),
    sing_4=as.factor(cutree(clst.sing,k=4)),
    sing_5=as.factor(cutree(clst.sing,k=5)),
    sing_6=as.factor(cutree(clst.sing,k=6)))

很遗憾,没有澄清实际问题; 但是,由于上述原因, usa, canada, nz的国家/地区和参数的usa, canada, nz1:3不匹配。 还有一些使用i + .建议i + . 不能解决此问题,因为在实际操作中使用了as.factor(cutree(X,k=X))

谢谢您的支持。

我不确定是否理解问题的实质,但这是一种使用所需的列名和值生成数据框的方法。

您可以更改~ function(i) i + . 是什么功能i (列被突变)你想,并修改了的n S IN setNames(n, n)纳入不同的值到您正在创建的函数(第一n )或更改的名称结果列(第二n )。

countries <- c('usa', 'canada', 'nz')
n <- 3:5

as.data.frame(matrix(1, nrow(df), length(n))) %>% 
  rename_all(~countries) %>%
  mutate_all(map(setNames(n, n), ~ function(i) i + .)) %>% 
  select(-countries) %>% 
  bind_cols(df)

#   usa_3 canada_3 nz_3 usa_4 canada_4 nz_4 usa_5 canada_5 nz_5 id  a b  c d e
# 1     4        4    4     5        5    5     6        6    6  1  3 2 12 9 1
# 2     4        4    4     5        5    5     6        6    6  2 10 1  3 7 2
# 3     4        4    4     5        5    5     6        6    6  3  4 1  0 8 0
# 4     4        4    4     5        5    5     6        6    6  4  0 0  3 0 2
# 5     4        4    4     5        5    5     6        6    6  5 15 3  1 0 2

不知道您在做什么,但是也许这有助于澄清问题。

library(tidyverse)

df <- data.frame(
  id  = c(1:5),
  a   = c(3,10,4,0,15),
  b   = c(2,1,1,0,3),
  c   = c(12,3,0,3,1),
  d   = c(9,7,8,0,0),
  e   = c(1,2,0,2,2)
)

ctry <- rep(c("usa", "ca", "nz"), each = 3)
nr <- rep(seq(3,5), times = 3)
df %>%
  as_tibble() %>%
  bind_cols(map_dfc(seq_along(ctry), ~1+nr[.x] %>%
                      rep(nrow(df))) %>%
              set_names(str_c(ctry, nr, sep = "_")))

# A tibble: 5 x 15
     id     a     b     c     d     e usa_3 usa_4 usa_5  ca_3  ca_4  ca_5  nz_3  nz_4  nz_5
  <int> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1     1     3     2    12     9     1     4     5     6     4     5     6     4     5     6
2     2    10     1     3     7     2     4     5     6     4     5     6     4     5     6
3     3     4     1     0     8     0     4     5     6     4     5     6     4     5     6
4     4     0     0     3     0     2     4     5     6     4     5     6     4     5     6
5     5    15     3     1     0     2     4     5     6     4     5     6     4     5     6

有点肮脏的解决方案,但它可以满足您的要求。 它结合了两个map_dfc函数。

library(dplyr)
library(purrr)

df <- tibble(id  = c(1:5),
             a   = c(3,10,4,0,15),
             b   = c(2,1,1,0,3),
             c   = c(12,3,0,3,1),
             d   = c(9,7,8,0,0),
             e   = c(1,2,0,2,2))

create_postfix_cols <- function(df, country, n) {
  # df = a dataframe
  # country = suffix value (e.g. "canada")
  # n = vector of postfix values (e.g. 3:5)

  map2_dfc(.x = rep(country, length(n)),
           .y = n,
           ~ tibble(col = rep(1 + .y, nrow(df))) %>%
             set_names(paste(.x, .y, sep = "_")))
}

countries <- c("usa", "canada", "nz")
n <- 3:5

df %>%
  bind_cols(map_dfc(.x = countries, ~create_postfix_cols(df, .x, n)))


# A tibble: 5 x 15
     id     a     b     c     d     e usa_3 usa_4 usa_5 canada_3 canada_4 canada_5
  <int> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>    <dbl>    <dbl>    <dbl>
1     1     3     2    12     9     1     4     5     6        4        5        6
2     2    10     1     3     7     2     4     5     6        4        5        6
3     3     4     1     0     8     0     4     5     6        4        5        6
4     4     0     0     3     0     2     4     5     6        4        5        6
5     5    15     3     1     0     2     4     5     6        4        5        6
# ... with 3 more variables: nz_3 <dbl>, nz_4 <dbl>, nz_5 <dbl>

这是基本的R解决方案。 您可以根据需要重新排列列,但这应该可以开始:

# Create column names using an index and country names
idx <- 3:5
countries <- c("usa", "canada", "nz")
new_columns <- unlist(lapply(countries, paste0, "_", idx))

# Adding new values using index & taking advantage of recycling
df[new_columns] <- sort(rep(1+idx, nrow(df)))
df
  id  a b  c d e usa_3 usa_4 usa_5 canada_3 canada_4 canada_5 nz_3 nz_4 nz_5
1  1  3 2 12 9 1     4     5     6        4        5        6    4    5    6
2  2 10 1  3 7 2     4     5     6        4        5        6    4    5    6
3  3  4 1  0 8 0     4     5     6        4        5        6    4    5    6
4  4  0 0  3 0 2     4     5     6        4        5        6    4    5    6
5  5 15 3  1 0 2     4     5     6        4        5        6    4    5    6

或者,如果您愿意:

# All in one long line
df[unlist(lapply(countries, paste0, "_", idx))] <- sort(rep(1+idx, nrow(df)))

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM