замена выброса их средним значением для многослойных данных в R с использованием dplyr - PullRequest
0 голосов
/ 29 ноября 2018

Мои df с различными клиентами вместе с их данными о продажах, но есть некоторые выбросы, и я хотел бы заменить выбросы (которые выше 2 SD ниже среднего) (μ ± 2σ) и заменить их на каждое среднее значение customer_id.

structure(list(Date = c("6/29/2014", "7/6/2014", "7/13/2014", 
"7/20/2014", "7/27/2014", "8/3/2014", "8/10/2014", "8/17/2014", 
"8/24/2014", "6/29/2014", "7/6/2014", "7/13/2014", "7/20/2014", 
"7/27/2014", "8/3/2014", "8/10/2014", "8/17/2014", "8/24/2014", 
"7/6/2014", "7/13/2014", "7/20/2014", "7/27/2014", "8/3/2014", 
"8/10/2014", "8/17/2014", "8/24/2014"), customer_id = c("9000A", 
"9000A", "9000A", "9000A", "9000A", "9000A", "9000A", "9000A", 
"9000A", "80A09", "80A09", "80A09", "80A09", "80A09", "80A09", 
"80A09", "80A09", "80A09", "Y90BC", "Y90BC", "Y90BC", "Y90BC", 
"Y90BC", "Y90BC", "Y90BC", "Y90BC"), sales = c(20L, 40L, 0L, 
42L, 56L, 90L, 500L, 23L, 60L, 200L, 234L, 500L, 450L, 0L, 900L, 
459L, 347L, 895L, 380L, 390L, 432L, 320L, 400L, 10L, 0L, 1000L
)), class = "data.frame", row.names = c(NA, -26L))

Может кто-нибудь помочь мне, вероятно, с помощью dplyr.Примечание: все значения «0» и продажи, не входящие в (μ ± 2σ), должны быть заменены средними значениями с учетом их customer_id

1 Ответ

0 голосов
/ 29 ноября 2018

И еще один способ с dplyr:)

не был полностью уверен, хотите ли вы, чтобы сокращение было основано на глобальном среднем или сгруппировано по клиенту, поэтому есть 2 версии.

edit: для проверки на

sales > mean(sales) + 2*sd(sales) | sales < mean(sales) - 2*sd(sales) | sales == 0

code

# version to check for > global mean + 2 * global sd
# if sales-value > global cutoff sales-value gets replaced by customer mean
test_data2 = 
  test_data %>% group_by(customer_id) %>% 
  mutate(sales = ifelse(sales > mean(test_data$sales) + 2*sd(test_data$sales), mean(sales), sales))

# version to check for mean per customer + 2 * sd per customer
# if sales-value > customer cutoff sales-value gets replaced by customer mean
test_data2 = 
  test_data %>% group_by(customer_id) %>% 
  mutate(sales = ifelse(sales > mean(sales) + 2*sd(sales), mean(sales), sales))



### check if this is what we want

# calc global mean + global sd + cutoff global
mean(test_data$sales)
sd(test_data$sales)
mean(test_data$sales) + 2*sd(test_data$sales)

# calc mean, sd, cutoff for each customer
test_data %>% group_by(customer_id) %>% summarise(mean = mean(sales), sd = sd(sales), cutoff = mean + 2*sd(sales))



test_data$sales2 = test_data2$sales

test_data %>% filter(customer_id == "80A09")
test_data %>% filter(customer_id == "9000A")
test_data %>% filter(customer_id == "Y90BC")

отдельный управляющий код, чтобы получить noвывод между обеими версиями:

df = structure(list(Date = c("6/29/2014", "7/6/2014", "7/13/2014", 
                                    "7/20/2014", "7/27/2014", "8/3/2014", "8/10/2014", "8/17/2014", 
                                    "8/24/2014", "6/29/2014", "7/6/2014", "7/13/2014", "7/20/2014", 
                                    "7/27/2014", "8/3/2014", "8/10/2014", "8/17/2014", "8/24/2014", 
                                    "7/6/2014", "7/13/2014", "7/20/2014", "7/27/2014", "8/3/2014", 
                                    "8/10/2014", "8/17/2014", "8/24/2014"), customer_id = c("9000A", 
                                                                                            "9000A", "9000A", "9000A", "9000A", "9000A", "9000A", "9000A", 
                                                                                            "9000A", "80A09", "80A09", "80A09", "80A09", "80A09", "80A09", 
                                                                                            "80A09", "80A09", "80A09", "Y90BC", "Y90BC", "Y90BC", "Y90BC", 
                                                                                            "Y90BC", "Y90BC", "Y90BC", "Y90BC"), sales = c(20L, 40L, 0L, 
                                                                                                                                           42L, 56L, 90L, 500L, 23L, 60L, 200L, 234L, 500L, 450L, 0L, 900L, 
                                                                                                                                           459L, 347L, 895L, 380L, 390L, 432L, 320L, 400L, 10L, 0L, 1000L
                                                                                            )), class = "data.frame", row.names = c(NA, -26L))



test_data = df %>% group_by(customer_id) %>% mutate(sales =ifelse( sales > mean(sales) + 2*sd(sales) | sales < mean(sales) - 2*sd(sales) | sales == 0,mean(sales),sales))
test_data$sales_old = df$sales

df %>% group_by(customer_id) %>% summarise(mean = mean(sales), sd = sd(sales), cutoff = mean + 2*sd(sales))


test_data %>% filter(customer_id == "80A09" & sales != sales_old)
test_data %>% filter(customer_id == "9000A" & sales != sales_old)
test_data %>% filter(customer_id == "Y90BC" & sales != sales_old)

вывод:

> df %>% group_by(customer_id) %>% summarise(mean = mean(sales), sd = sd(sales), cutoff = mean + 2*sd(sales))
# A tibble: 3 x 4
  customer_id  mean    sd cutoff
  <chr>       <dbl> <dbl>  <dbl>
1 80A09       443.   301.  1045.
2 9000A        92.3  155.   402.
3 Y90BC       366.   310.   986.
> test_data %>% filter(customer_id == "80A09" & sales != sales_old)
# A tibble: 1 x 4
# Groups:   customer_id [1]
  Date      customer_id sales sales_old
  <chr>     <chr>       <dbl>     <int>
1 7/27/2014 80A09        443.         0
> test_data %>% filter(customer_id == "9000A" & sales != sales_old)
# A tibble: 2 x 4
# Groups:   customer_id [1]
  Date      customer_id sales sales_old
  <chr>     <chr>       <dbl>     <int>
1 7/13/2014 9000A        92.3         0
2 8/10/2014 9000A        92.3       500
> test_data %>% filter(customer_id == "Y90BC" & sales != sales_old)
# A tibble: 2 x 4
# Groups:   customer_id [1]
  Date      customer_id sales sales_old
  <chr>     <chr>       <dbl>     <int>
1 8/17/2014 Y90BC        366.         0
2 8/24/2014 Y90BC        366.      1000
...