【问题标题】:dplyr: replace NAs with zeros after group_by, while keeping original NAs in Rdplyr:在 group_by 之后用零替换 NA,同时在 R 中保留原始 NA
【发布时间】:2021-05-20 19:31:47
【问题描述】:

我正在创建一个新变量,并且由于 NA 以及只有一些人符合分组标准,我最终在我的最终数据集中创建了许多新的 NA。

Here 是数据。

更新示例数据框:

id    age    year   var1
4     KL      2007   15
1     KL      2008   10
2     KL      2008   20
4     AG      2008   NA
3     AG      2008   5    
3     SU      2009   NA
4     SU      2009   NA    
4     LL      2011   NA

数据框细微差别:

  1. age=="KL" & year==2007 只有 1 行(有值)
  2. age=="KL" & year==2008 有多行(带值)
  3. age=="AG" & year==2008 有多行(带有值和 NA)
  4. age=="SU" & year==2009 有多行(仅限 NA)
  5. age=="LL" & year==2011 只有 1 行(带 NA)

示例公式:

df<-df %>%
    group_by(age, year) %>% 
    mutate(new_var1=((var1-mean(var1, na.rm=T))/(1*(sd(var1, na.rm=T)))))

当前输出:

id    age    year   var1    new_var1
4     KL      2007   15      NA
1     KL      2008   10     -0.7071068
2     KL      2008   20      0.7071068
4     AG      2008   NA      NA
3     AG      2008   5       NA
3     SU      2009   NA      NA
4     SU      2009   NA      NA
4     LL      2011   NA      NA

期望的输出:

id    age    year   var1    new_var1
4     KL      2007   15      0
1     KL      2008   10     -0.7071068
2     KL      2008   20      0.7071068
4     AG      2008   NA      NA
3     AG      2008   5       0
3     SU      2009   NA      NA
4     SU      2009   NA      NA
4     LL      2011   NA      NA

我怎样才能保留现有的 NA(那些是缺失数据的真实实例),同时强制新 NA 的任何实例(因为该行是唯一的记录)为 0 而不是 NA?

非常感谢dplyr 解决方案。

我知道如何用零替换 NA(例如,mutate(new_var1=ifelse(is.na(new_var1), 0, new_var1))),但这会替换所有 NA,而不仅仅是新的 NA。

【问题讨论】:

  • id 4 的最后一行的输出是什么
  • 就像一个菜鸟一样,我没有指定年龄的编码(它是分类的,而不是数字的)。我还在问题中添加了真实数据。
  • 这并不重要,因为我们正在进行分组并且值是根据数字计算的
  • 嗯。对我来说,这一定是一件非常愚蠢的事情。不过我不想再浪费你的时间了,所以谢谢你的帮助!

标签: r group-by dplyr


【解决方案1】:

我们可以使用if/else 创建一个条件来检查单个观察值,如果不是 NA,则返回 0 否则进行计算

library(dplyr)
df %>% 
   group_by(age, year) %>% 
  mutate(var1 = if(n() == 1 && !is.na(var1) | sum(!is.na(var1)) == 1) 0 * var1
  else ((var1-mean(var1, na.rm=TRUE))/(1*(sd(var1, na.rm=TRUE))))) %>%
    ungroup

-输出

# A tibble: 8 x 4
     id age    year   var1
  <int> <chr> <int>  <dbl>
1     4 KL     2007  0    
2     1 KL     2008 -0.707
3     2 KL     2008  0.707
4     4 AG     2008 NA    
5     3 AG     2008  0    
6     3 SU     2009 NA    
7     4 SU     2009 NA    
8     4 LL     2011 NA    

数据

df <- structure(list(id = c(4L, 1L, 2L, 4L, 3L, 3L, 4L, 4L), age = c("KL", 
"KL", "KL", "AG", "AG", "SU", "SU", "LL"), year = c(2007L, 2008L, 
2008L, 2008L, 2008L, 2009L, 2009L, 2011L), var1 = c(15L, 10L, 
20L, NA, 5L, NA, NA, NA)), class = "data.frame", row.names = c(NA, 
-8L))

【讨论】:

  • 出于某种原因,当我尝试应用您的解决方案时,它会为整个列返回 NaN。您能否帮我解决为什么它对您的答案有效,但对我无效?
  • @BlunderingEcologist 这是基于您展示的相同示例吗?在您的原始数据中,我猜有些组有不止一个观察值,而且它们都是 NA,这会导致 NaN 而您使用 mean 进行计算
  • 啊,我想可能是这样。我尝试使用上面的一个精简示例来避免让人不知所措,但我认为我错过了一些重要的细微差别?
  • @BlunderingEcologist 我没有在此处包含该条件。此外,可能存在单个非 NA 元素并且 sd 可以返回 NA
  • 我认为这在我的原始数据集中更常见(单个非 NA 元素,然后由于 sd() 函数而最终给出 NA)。是否可以修改您的答案以允许这些条件? (我很抱歉没有提出更好的问题)。我将更新我的示例数据集以尝试包含这些内容。
【解决方案2】:

一个选项可能是:

df <- structure(list(id = c(4L, 1L, 2L, 4L, 3L, 3L, 4L, 4L), 
                     age = c("KL", "KL", "KL", "AG", "AG", "SU", "SU", "LL"),
                     year = c(2007L, 2008L, 2008L, 2008L, 2008L, 2009L, 2009L, 2011L), 
                     var1 = c(15L, 10L, 20L, NA, 5L, NA, NA, NA)), class = "data.frame", row.names = c(NA, 
                                                                                                                                                                                                                                            -8L))
library(dplyr)

df %>%
  group_by(age, year) %>% 
  mutate(new_var1=ifelse(is.nan(scale(var1)), 0, scale(var1))) %>% 
  ungroup()
#> # A tibble: 8 x 5
#>      id age    year  var1 new_var1[,1]
#>   <int> <chr> <int> <int>        <dbl>
#> 1     4 KL     2007    15        0    
#> 2     1 KL     2008    10       -0.707
#> 3     2 KL     2008    20        0.707
#> 4     4 AG     2008    NA       NA    
#> 5     3 AG     2008     5        0    
#> 6     3 SU     2009    NA       NA    
#> 7     4 SU     2009    NA       NA    
#> 8     4 LL     2011    NA       NA

library(data.table)
setDT(df)[, new_var1 :=ifelse(is.nan(scale(var1)), 0, scale(var1)), by = list(age, year)][]
#>    id age year var1   new_var1
#> 1:  4  KL 2007   15  0.0000000
#> 2:  1  KL 2008   10 -0.7071068
#> 3:  2  KL 2008   20  0.7071068
#> 4:  4  AG 2008   NA         NA
#> 5:  3  AG 2008    5  0.0000000
#> 6:  3  SU 2009   NA         NA
#> 7:  4  SU 2009   NA         NA
#> 8:  4  LL 2011   NA         NA

由reprex package (v2.0.0) 于 2021 年 5 月 21 日创建

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-03-19
    • 1970-01-01
    • 2014-03-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-01
    相关资源
    最近更新 更多