【问题标题】:Use of ifelse to assign values to a new dataframe column in R使用 ifelse 将值分配给 R 中的新数据框列
【发布时间】:2020-12-30 13:48:17
【问题描述】:

我有一个时间序列数据框,想创建一个新的数值列,其值是现有数值列的函数,并根据星期几列分配。

例如,我需要如下代码:

Day <- c("Mo", "Mo", "Mo", "Tu", "Tu", "We", "We", "We", "We", "Th")
Val <- c(1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000)
df <- data.frame(cbind(Day,Val))
df$Adj <- ifelse(df$Day == "Mo" || df$Day == "Tu", 
                 as.numeric(levels(df$Val)) + 1, 
                 as.numeric(levels(df$Val)) + 2)

返回:

   Day  Val  Adj
1   Mo 1000 1001
2   Mo 1000 1001
3   Mo 1000 1001
4   Tu 1000 1001
5   Tu 1000 1001
6   We 1000 1002
7   We 1000 1002
8   We 1000 1002
9   We 1000 1002
10  Th 1000 1002

不幸的是,我的代码仅将 Adj 作为 1001 列返回。

   Day  Val  Adj
1   Mo 1000 1001
2   Mo 1000 1001
3   Mo 1000 1001
4   Tu 1000 1001
5   Tu 1000 1001
6   We 1000 1001
7   We 1000 1001
8   We 1000 1001
9   We 1000 1001
10  Th 1000 1001

我已经在 "We" 行之一上测试了 ifelse,它成功了……

> ifelse(df$Day[6] == "Mo" || df$Day[6] == "Tu", 
+        as.numeric(levels(df$Val[6])) + 1, 
+        as.numeric(levels(df$Val[6])) + 2)
[1] 1002

...但我似乎无法让它在整个列上工作,我理解这是 ifelse 函数相对于循环 if-else 语句的优势之一。

我的方法基于我能找到的最相似的问题 (Create new column in dataframe using if {} else {} in R) 但没有快乐。我在这里错过了什么?

【问题讨论】:

  • 首先,将stringsAsFactors = TRUE 添加到data.frame() 中(在最新的R 版本中,stringsAsFactors 默认为FALSE)。然后将|| 替换为|,你的代码就可以工作了!

标签: r if-statement dplyr


【解决方案1】:

使用 dplyr:

Day <- c("Mo", "Mo", "Mo", "Tu", "Tu", "We", "We", "We", "We", "Th")
Val <- c(1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000)
df <- data.frame(Day,Val)

library(dplyr)

df %>% rowwise %>% mutate(Adj = ifelse(Day == "Mo" || Day == "Tu", 
                           Val + 1, 
                           Val + 2))
#> # A tibble: 10 x 3
#>    Day     Val   Adj
#>    <chr> <dbl> <dbl>
#>  1 Mo     1000  1001
#>  2 Mo     1000  1001
#>  3 Mo     1000  1001
#>  4 Tu     1000  1001
#>  5 Tu     1000  1001
#>  6 We     1000  1002
#>  7 We     1000  1002
#>  8 We     1000  1002
#>  9 We     1000  1002
#> 10 Th     1000  1002

请注意,df &lt;- data.frame(cbind(Day,Val)) 将 Val 转换为 character,这可能不是您要查找的内容。
您可以将其简化为df &lt;- data.frame(Day,Val)

【讨论】:

    【解决方案2】:

    我们可以使用%in% 来检查Day 的值是否为c('Mo', 'Tu'),相应地在Val 上加1 或2。

    df <- transform(df, Adj = Val + ifelse(Day %in% c('Mo', 'Tu'), 1, 2))
    #you can do this without `ifelse` as well.
    #df <- transform(df, Adj = Val + as.integer(!Day %in% c('Mo', 'Tu')) + 1)
    df
    
    #   Day  Val  Adj
    #1   Mo 1000 1001
    #2   Mo 1000 1001
    #3   Mo 1000 1001
    #4   Tu 1000 1001
    #5   Tu 1000 1001
    #6   We 1000 1002
    #7   We 1000 1002
    #8   We 1000 1002
    #9   We 1000 1002
    #10  Th 1000 1002
    

    【讨论】:

      【解决方案3】:

      为了尊重与此问题相关的经验水平,问题中使用的那些使用循环的函数也用于提供答案。实现预期结果的一种方法可以使用以下代码:

      Adj <- list()                                       # assign an empty list
      
      for(i in 1: nrow(df)) {                             # For loop
         
          if(df$Day[i] == "Mo" || df$Day[i] == "Tu") {     # the conditional ifelse loop
             Adj[i] <- c(1000 + 1)                         # The 1000 can be replaced w/ Val[i] 
        } else { 
             Adj[i] <- c(1000 + 2)
          }
         }
      
      Adj <- as.numeric(paste0(Adj))                        # Convert list to numeric vector
      
      df <- cbind(df, Adj)                                 # Combine the df with the new vector
      df                                                    # print results
      

      结果可以从这个link:查看

      【讨论】:

        猜你喜欢
        • 2021-07-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-06-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多