【问题标题】:R,dplyr: How to replace 0 values based conditional on size of group_byR,dplyr:如何根据 group_by 的大小替换 0 个值
【发布时间】:2019-09-07 02:38:18
【问题描述】:

我正在尝试根据 group_by 的大小将列中的 0 值替换为大型数据集的组的中值。

set.seed(10000)
Data <- data.frame(
    X = as.numeric(c(0,2,3,4,5,6,7,8,9,0)),
    Y = c("no","yes","yes","yes","yes","yes","yes","yes","yes","yes"),
    Z = c(F,T,T,T,T,F,F,F,T,T)
)

# change 0 in the 10 spot to median
Data <- Data %>%
    # group by Y and Z then
    group_by(Y,Z) %>%
    # if the size of the group is less than 2 and if X is NA change it to 10
    # else leave it as X else (if group size 2 or greater) leave value as NA then
    mutate(X = ifelse(n()<2,ifelse(X==0,median(X),X),X)) 

# change 0 in 1 spot to median
Data <- Data %>%
    # group by Y then
    group_by(Y) %>%
    # if the size of the group is larger than 2 and if X is NA change it to 1
    # else leave is as X else(if group size 3 or larger) leave value as X
    mutate(X = ifelse(n()<3,ifelse(X==0,median(X),X),X))

导致错误:

n > 1 中的错误:

比较 (6) 仅适用于原子和列表类型

我希望 X 列是上述代码之后 1:10 的序列。

这是我在使用大型数据集时遇到的问题的概括,我试图将 0 值作为不同组的中位数,以组的大小为条件,我得到与上述相同的错误。

【问题讨论】:

  • 我认为您希望 n() 在您的 ifs 中并且不确定条件,因为您的第一个 mutate 用 NA 填充 X 列,最后是 10,因为 yes 组有长度9.
  • 我不听你的问题。在您声明的代码上方:“我正在尝试根据 group_by 的大小有条件地将列中的 NA 值替换为中值”。然而,在您不使用任何中间值的代码中,您需要一些固定值(1 和 10)。你想要/期待哪一个?
  • 我也不清楚您要做什么。您能否为您提供的示例数据提供您的预期输出?此外,不需要set.seed,因为您不会生成随机数据。

标签: r if-statement group-by dplyr


【解决方案1】:

我找不到如何回答您的确切问题,但我希望这可以为您指明正确的方向(这也是 data.table 解决方案)。

假设您想要列的 mean 而不是任何 NA,这取决于组的大小,zoo 包中的一个函数可以提供帮助:

# load libraries

library(zoo)
library(data.table)

# convert Data to a data.table

setDT(Data)

现在,我们将使用函数 zoo::na.aggregate 替换为 mean 任何 NA。但是我们需要引入组的大小作为条件。所以我先一步一步来:

# create a column with the number of elements in the group. It'll be removed later:

Data[, n:= .N, by = Y]

# Create a new X column with the NAs replaced by the mean, in case the group is larger than 2, or an arbitrary number -I choosed 100-, if the group is less or equal than 2:

Data[, newX := ifelse(n >2, na.aggregate(x), 100), by = Y]

# Now you can optionally copy newX to X:

Data[, X := newX]

# and delete n and newX:

Data[, c("n", "newX") := NULL]

当然,您可以通过直接分配给X 来跳过X := newX 部分,但它认为它比一步一步的过程更晦涩。

【讨论】:

    【解决方案2】:

    看看这是否适合你:

    library(tidyverse)
    
    set.seed(10000)
    Data <- data.frame(
      X = c(NA,2,3,4,5,6,7,8,9,NA),
      Y = c("yes","yes","yes","yes","yes","yes","yes","yes","yes","no"),
      Z = c(T,F,F,F,F,F,F,F,F,T)
    )
    
    # change NA in the 10 spot to 10
    Data %>%
      group_by(Y) %>%
      mutate(count = n()) %>%
      mutate(X = ifelse(count < 2, ifelse(is.na(X), 10, X), NA)) %>%
      select(-count)
    
    
    # change NA in 1 spot to 1
    Data %>%
      group_by(Y,Z) %>%
      mutate(count = n()) %>%
      mutate(X = ifelse(count < 3, ifelse(is.na(X), 1, X), X)) %>%
      select(-count)
    
    
    
    # You can bypass the count column 
    Data %>%
      group_by(Y) %>%
      mutate(X = ifelse(n() < 2, ifelse(is.na(X), 10, X), NA)) 
    

    【讨论】:

    • 这并不完全有效。第一个块使列 NA 和 10,第二个块有效,第三个块不起作用,这是我在上面尝试的。
    猜你喜欢
    • 2016-06-14
    • 1970-01-01
    • 1970-01-01
    • 2023-04-09
    • 2020-11-19
    • 1970-01-01
    • 2021-04-17
    • 2017-03-01
    • 1970-01-01
    相关资源
    最近更新 更多