R, dplyr: как заменить 0 значений в зависимости от размера group_by - PullRequest
0 голосов
/ 17 апреля 2019

Я пытаюсь заменить 0 значений в столбце на основе условного размера их group_by срединным значением группы для большого набора данных.

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 значений в качестве медианы для другой группы в зависимости от размера группы, и я получаю ту же ошибку, что и выше.

Ответы [ 2 ]

0 голосов
/ 17 апреля 2019

Я не могу найти, как ответить на ваш точный вопрос, но я надеюсь, что это направит вас в правильном направлении (это также решение 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 := newX, прямо указав на X, но это показалось немного более неясным, чем пошаговый процесс.

0 голосов
/ 17 апреля 2019

Посмотрите, работает ли это для вас:

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)) 
...