100 самых высоких и самых низких наблюдений для отсортированных нескольких столбцов в R - PullRequest
1 голос
/ 07 апреля 2020

Я придумал более оптимальное полу-решение. Я отсортировал данные по сектору и объему.

df <- structure(list(Customer = structure(1:17, .Label = c("A", "B", 
"C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", 
"P", "Q"), class = "factor"), Sector = structure(c(1L, 1L, 1L, 
1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 3L, 3L, 3L, 3L, 3L), .Label = c("Aviation", 
"Biotech", "Construction"), class = "factor"), Volume = c(-5000L, 
-3000L, 4000L, 6000L, 7000L, 9000L, -4000L, -1500L, 2000L, 3000L, 
5000L, 6000L, -7000L, -4000L, 5000L, 7000L, 8000L)), 
class = "data.frame", row.names = c(NA,-17L))

РЕДАКТИРОВАНИЕ:

## > df
##   Customer  Sector      Volume
##     A      Aviation     - 5000
##     B      Aviation     - 3000
##     C      Aviation       4000
##     D      Aviation       6000
##     E      Aviation       7000
##     F      Aviation       9000
##     G      Biotech      - 4000
##     H      Biotech      - 1500
##     I      Biotech        2000
##     J      Biotech        3000
##     K      Biotech        5000
##     L      Biotech        6000
##     M      Construction - 7000
##     N      Construction - 4000
##     O      Construction   5000
##     P      Construction   7000
##     Q      Construction   8000

Допустим, я хотел бы оставить 2 самых высоких и самых низких клиентов в каждом секторе. Итак, мой финальный стол должен выглядеть следующим образом:

## > df
##   Customer  Sector      Volume
##     A      Aviation     - 5000
##     B      Aviation     - 3000
##     E      Aviation       7000
##     F      Aviation       9000
##     G      Biotech      - 4000
##     H      Biotech      - 1500
##     K      Biotech        5000
##     L      Biotech        6000
##     M      Construction - 7000
##     N      Construction - 4000
##     P      Construction   7000
##     Q      Construction   8000

Единственное отличие состоит в том, что я хотел бы видеть 100 / максимум 100 клиентов в секторе в моем случае вместо 2.

Ответы [ 2 ]

1 голос
/ 07 апреля 2020

Используя библиотеку (data.table), вы получаете желаемый результат, используя следующее:

library(data.table)
# convert the data.frame into a data.table
setDT(df) 
# sort the data.table by Volume
setkey(df,Volume)
# rbind the  smallest 2 volumes by sector and with the highest 
# 2 volumes by sector
rbind(df[,tail(.SD,2),Sector],
      df[,head(.SD,2),Sector])[order(Customer,Sector)]


##           Sector Customer Volume
##  1:     Aviation        A  -5000
##  2:     Aviation        B  -3000
##  3:     Aviation        E   7000
##  4:     Aviation        F   9000
##  5:      Biotech        G  -4000
##  6:      Biotech        H  -1500
##  7:      Biotech        K   5000
##  8:      Biotech        L   6000
##  9: Construction        M  -7000
## 10: Construction        N  -4000
## 11: Construction        P   7000
## 12: Construction        Q   8000
1 голос
/ 07 апреля 2020

Поскольку каждый столбец отсортирован, вы можете удалить значения NA с помощью na.omit и использовать head и tail для получения верхнего и нижнего значений 100.

sapply(df[-1], function(x) {x1 <- na.omit(x);c(head(x1, 100), tail(x1, 100))})

Или аналогичным образом используя apply с MARGIN = 2

apply(df[-1], 2, function(x) {x1 <- na.omit(x);c(head(x1, 100), tail(x1, 100))})

Мы также можем создать индекс для подмножества:

sapply(df[-1], function(x) 
        {x1 <- na.omit(x);x1[c(1:100,(length(x1) - 100):length(x1))]})

РЕДАКТИРОВАТЬ

Для обновленных данных мы можем использовать slice из dplyr.

library(dplyr)
df %>% group_by(Sector) %>% slice(c(1:2, (n() -1):n()))


#  Customer Sector       Volume
#   <fct>    <fct>         <int>
# 1 A        Aviation      -5000
# 2 B        Aviation      -3000
# 3 E        Aviation       7000
# 4 F        Aviation       9000
# 5 G        Biotech       -4000
# 6 H        Biotech       -1500
# 7 K        Biotech        5000
# 8 L        Biotech        6000
# 9 M        Construction  -7000
#10 N        Construction  -4000
#11 P        Construction   7000
#12 Q        Construction   8000

Или другим способом, используя top_n.

bind_rows(df %>% group_by(Sector) %>% top_n(2, Volume),
          df %>% group_by(Sector) %>% top_n(-2, Volume)) %>%
arrange(Sector)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...