【问题标题】:Mutate multiple columns with conditions using dplyr使用 dplyr 改变具有条件的多个列
【发布时间】:2019-02-09 22:50:19
【问题描述】:

我有一个大型数据集,我想为其创建 50 个新变量,其中的值取决于先前列中的值,并且变量的名称反映了这一事实。为了更容易理解,这里举个例子:

df <- tibble("a" = runif(10,1990,2000),
         "event" = 1995) %>%
      mutate("relative_event" = a - event)

现在有了这个数据集,我想创建虚拟变量,如果特定观察是在事件发生前一年、前 2 年等,以及向前,则编码。一种笨拙的方法(有效)是:

df <- df %>%
  mutate("event_b1" = ifelse( (relative_event<=0) & (relative_event > -1),1,0)) %>%
  mutate("event_b2" = ifelse( (relative_event<=-1) & (relative_event > -2),1,0)) %>% #etc with more lagx
  mutate("event_f1" = ifelse( (relative_event>0) & (relative_event < 1),1,0)) %>%
  mutate("event_f2" = ifelse( (relative_event>1) & (relative_event < 2 ),1,0)) #etc with more forward

其中 b1 代表“一年前”,f2 代表“两年前”。结果如下所示:

 A tibble: 10 x 7
       a event relative_event event_b1 event_b2 event_f1 event_f2
    <dbl> <dbl>          <dbl>    <dbl>    <dbl>    <dbl>    <dbl>
  1 1993.  1995         -1.94         0        1        0        0
  2 1992.  1995         -2.59         0        0        0        0
  3 2000.  1995          4.75         0        0        0        0
  4 1998.  1995          3.25         0        0        0        0
  5 1991.  1995         -3.88         0        0        0        0
  6 1992.  1995         -3.02         0        0        0        0
  7 1996.  1995          1.08         0        0        0        1
  8 1994.  1995         -1.04         0        1        0        0
  9 1993.  1995         -2.22         0        0        0        0
 10 1995.  1995         -0.302        1        0        0        0

由于我要创建 50 多个列,我想知道如何自动创建,这样我就不必复制粘贴 49 次并手动更改条件和变量名称。我花了一些时间在这个thread、这个one 和CV 上查看SO,但我仍然一无所知。我尝试了以下不起作用的代码:

for (i in 0:10) {

  if (i<0) {

    event_bi  <- paste0("event_b",i)
    df <- df %>%
      mutate(get(event_bi) = ifelse((relative_event<=-(i-1)) & (relative_event>-i),1,0)) 

  } 
}

理想情况下,我想学习如何使用 dplyr 进行操作,但如果有明显的 Base R 解决方案,我也很乐意学习它。

谢谢!

【问题讨论】:

  • 当您从 0:10 运行索引 i - 当然,当您的条件是 (i &lt; 0) 时,您的代码将无法工作。此外,您是否有充分的理由想要获得 50 个不同的列?据我了解,您基本上是在为不同的条件分配值relative event - 这可以全部放在一个列中。但我可能没有正确理解你的问题

标签: r dplyr non-standard-evaluation


【解决方案1】:

虽然我更喜欢@Patrick 建议的将所有变量都放在一个列中的解决方案(虽然我会使用类似%&gt;% mutate(new_col = case_when(etc...)) 的东西,但这里是for-loop 的一种方式

# I changed your data a tiny bit
df <- tibble("a" = sample(1990:2000, size = 10),  # better to use 'sample' then 'runif' !
             "event" = 1995) %>% mutate("relative_event" = a - event)

现在实际工作

for (i in min(df$relative_event):max(df$relative_event)) {

# the indexing value is your difference in years. So you have to run the index from the lowest difference to the highest. 

if( i < 0 ) {
  df[[paste0('event_b', abs(i))]] <- ifelse(i == df$relative_event, 1, 0)
  } 
  if( i >= 0 ) {
    df[[paste0('event_f', abs(i))]] <- ifelse(i == df$relative_event, 1, 0)
    df
  } 
}  

# A tibble: 10 x 14
       a event relative_event event_b5 event_b4 event_b3 event_b2 event_b1
   <int> <dbl>          <dbl>    <dbl>    <dbl>    <dbl>    <dbl>    <dbl>
 1  1990  1995             -5        1        0        0        0        0
 2  1992  1995             -3        0        0        1        0        0
 3  1991  1995             -4        0        1        0        0        0
 4  2000  1995              5        0        0        0        0        0
 5  1998  1995              3        0        0        0        0        0
 6  1993  1995             -2        0        0        0        1        0
 7  1996  1995              1        0        0        0        0        0
 8  1997  1995              2        0        0        0        0        0
 9  1994  1995             -1        0        0        0        0        1
10  1999  1995              4        0        0        0        0        0
# ... with 6 more variables: event_f0 <dbl>, event_f1 <dbl>, event_f2 <dbl>,
#   event_f3 <dbl>, event_f4 <dbl>, event_f5 <dbl>

如果您不想遍历所有可能的年份差异 - (这将创建“空”列) - 您可以简单地使用 unique(df$relative_event) 创建一个向量并通过该向量运行 i

【讨论】:

  • 谢谢 Tjebo,我喜欢你的方法,虽然它不是很整洁,但可读性很好
【解决方案2】:

我不会声称这是完整的答案,但希望这会刺激其他一些用户发表评论/发布

     # load packages
     pacman::p_load(tibble,dplyr,tidyr)

     # your dataframe
     df <- tibble("a" = runif(10,1990,2000),
                  "event" = 1995) %>%
       mutate("relative_event" = round(a - event),0)

     df$rel3 <- df$relative_event #initialize new column

     for(xx in 1:(length(df$relative_event))) {
       if (df$relative_event[xx] <=0) {
         df$rel3[xx] <- paste0('b',as.character(abs(df$relative_event[xx])))
         } else {
         #add preceding a for "after"
         df$rel3[xx] <- paste0('a',as.character(abs(df$relative_event[xx])))
       }
     }

然后您可以将rel3 中的值转换为df 中的列。

【讨论】:

  • 我同意将值放在一列中有点建议。我不会在这里使用 for 循环,而是使用条件语句来代替。但是一个接近 OP 在下面提出的解决方案
猜你喜欢
  • 1970-01-01
  • 2017-10-11
  • 2017-04-28
  • 1970-01-01
  • 2020-04-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-10
相关资源
最近更新 更多