如何使用mutate从for循环中的列表创建列

时间:2020-04-28 01:24:49

标签: r list for-loop dplyr mutate

我想知道是否有一种方法可以在for循环中使用mutate()函数从R中的列表创建多个列。

这是我的意思的示例:

问题:

我有一个数据框df,其中有2列:类别和等级。我想为df$category的每个元素添加一列,如果category列与迭代器匹配,则在该列中我希望为1。

library(dplyr)

df <- tibble(
  category = c("Art","Technology","Finance"),
  rating = c(100,95,50)
)

手动进行操作,我可以这样做:

df <-
  df %>% 
  mutate(art = ifelse(category == "Art", 1,0))

但是,当我有50个类别时会发生什么? (这与我最初遇到的问题很接近。这将需要很多时间!)

我尝试过的事情:

category_names <- df$category

for(name in category_names){

  df <-
    df %>% 
    mutate(name = ifelse(category == name, 1,0))

}

不幸的是,它似乎不起作用。

我很感激这个问题!

完整代码:

library(dplyr)

#Creates tibble
df <- tibble(
  category = c("Art","Technology","Finance"),
  rating = c(100,95,50)
)

#Showcases the operation I would like to loop over df
df <-
  df %>% 
  mutate(art = ifelse(category == "Art", 1,0))

#Creates a variable for clarity
category_names <- df$category

#For loop I tried
for(name in category_names){

  df <-
    df %>% 
    mutate(name = ifelse(category == name, 1,0))

}

我知道我实际上在做的是model.matrix()的形式;但是,在我发现该功能之前,我仍然感到困惑,为什么之前的工作没有用。

1 个答案:

答案 0 :(得分:3)

创建序列列后,我们可以使用pivot_wider

library(dplyr)
library(tidyr)
df %>% 
    mutate(rn = row_number(), n = 1) %>% 
    pivot_wider(names_from = category, values_from = n, 
             values_fill = list(n = 0)) %>%
    select(-rn)
# A tibble: 3 x 4
#  rating   Art Technology Finance
#   <dbl> <dbl>      <dbl>   <dbl>
#1    100     1          0       0
#2     95     0          1       0
#3     50     0          0       1

或者另一个选择是map

library(purrr)
map_dfc(unique(df$category),  ~  df %>%
                                 transmute(!! .x := +(category == .x))) %>% 
     bind_cols(df, .)
# A tibble: 3 x 5
#  category   rating   Art Technology Finance
#* <chr>       <dbl> <int>      <int>   <int>
#1 Art           100     1          0       0
#2 Technology     95     0          1       0
#3 Finance        50     0          0       1

如果我们需要for循环

for(name in category_names) df <- df %>% mutate(!! name := +(category == name))

或在base R中与table

cbind(df, as.data.frame.matrix(table(seq_len(nrow(df)), df$category)))
#    category rating Art Finance Technology
#1        Art    100   1       0          0
#2 Technology     95   0       0          1
#3    Finance     50   0       1          0