95% винсоризация по группам по нескольким переменным - PullRequest
0 голосов
/ 07 июня 2019

В моих реальных данных у меня есть несколько выбросов для нескольких переменных.Мои данные выглядят примерно так, как показано ниже, но цифры здесь совершенно случайные.Я хотел бы вытащить все точки данных, которые больше или меньше 2 SD, используя winsorization 95%.

df <- read.csv(header=TRUE, text="
id, group, test1, test2
1, 0, 57, 82
2, 0, 77, 80
3, 0, 67, 90
4, 0, 15, 70
5, 0, 58, 72
6, 1, 18, 44
7, 1, 44, 44
8, 1, 18, 46
9, 1, 20, 44
10, 1, 14, 38")

Мне известна функция winsorize в пакете robustHD, но яне уверен: как обеспечить, чтобы винсоризация учитывала две разные группы и включала несколько переменных в эту винсоризацию.

Я пробовал этот код для решения проблемы, но код не завершен:

library(robustHD)
library(dplyr)

new.df.wins = df %>% 
  group_by(group) %>%  
  mutate(measure_winsorized = winsorize(c(test1,test2)))

Возвращается ошибка, указывающая

Error: Column `measure_winsorized` must be length 45 (the group size) or one, not 90

Я открыт для других идей.Спасибо!

Ответы [ 2 ]

0 голосов
/ 07 июня 2019

Вы можете сделать версию winsorize(), которая работает с фреймами данных, и использовать ее с by()

# Example data
set.seed(1)
df2 <- round(matrix(rt(100, 4), 20), 3)
df2 <- data.frame(id=seq_len(nrow(df2)),
                  group=sort(rep(1:2, length=nrow(df2))),
                  test=df2)

df2[c(1:3, 11:13),]
#    id group test.1 test.2 test.3 test.4 test.5
# 1   1     1 -0.673 -1.227  0.015 -0.831  0.024
# 2   2     1 -0.584  1.059  1.492  0.833 -0.377
# 3   3     1  0.572  0.613 -1.924 -0.672  1.184
# 11 11     2  0.054  0.020  2.241 -0.103 -0.047
# 12 12     2  1.746 -0.788 -0.268 -1.921  4.577
# 13 13     2 -0.472 -1.294 -0.258  0.795 -1.110

# data frame version of winsorize
winsorizedf <- function(x, ...) {
    do.call(cbind, lapply(x, winsorize, ...))
}

# winsorize every column, except the two first ones, grouped by df2$group
w <- do.call(rbind,
    by(df2[, -(1:2)], df2$group, winsorizedf))

# combine the winsorized columns with the original id and group columns
dfw <- data.frame(df2[, 1:2], round(w, 2))

dfw[c(1:3, 11:13),]
#    id group test.1 test.2 test.3 test.4 test.5
# 1   1     1  -0.63  -1.23   0.02  -0.83   0.02
# 2   2     1  -0.58   1.06   1.49   0.26  -0.38
# 3   3     1   0.57   0.61  -1.60  -0.67   1.18
# 11 11     2   0.05   0.02   1.23  -0.10  -0.05
# 12 12     2   1.70  -0.79  -0.27  -1.92   4.58
# 13 13     2  -0.47  -1.07  -0.26   0.80  -1.11
0 голосов
/ 07 июня 2019

Подумайте о создании двух новых полей для каждого числового поля, подлежащего Winsorized:

new.df.wins <- df %>% 
                 group_by(group) %>%  
                 mutate(measure_winsorized_test1 = winsorize(test1),
                        measure_winsorized_test2 = winsorize(test2))

В качестве альтернативы с базовыми R ave:

new.df.wins <- within(df, {    
   measure_winsorized_test2 <- ave(test2, group, FUN=winsorize)
   measure_winsorized_test1 <- ave(test1, group, FUN=winsorize)    
})

Если вы хотите Winsorize оба одновременно,назначить сразу двум новым столбцам:

# TIDYVERSE (dplyr)
new.df.wins <- df %>% 
                 group_by(group) %>%  
                 mutate_at(.funs = list(wins = winsorize), .vars = vars(test1:test2))

# TINYVERSE (I.E. BASE R)
df[c("test1_wins", "test2_wins")] <- with(df, ave(cbind(test1, test2),  
                                                  group, FUN=winsorize))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...