Суммировать самые низкие значения в Dataframe?

Мой фрейм данных выглядит так:

View(df)
Product     Value
  a           2
  b           4 
  c           3
  d           10
  e           15
  f           5
  g           6
  h           4
  i           50
  j           20
  k           35
  l           25
  m           4
  n           6
  o           30
  p           4
  q           40
  r           5
  s           3
  t           40

Я хочу найти 9 самых дорогих продуктов и резюме остальных. Это должно выглядеть так:

Product     Value 
  d           10
  e           15
  i           50
  j           20
  k           35
  l           25
  o           30
  q           40
  t           40
 rest         46

Отдых - это сумма остальных 11 продуктов. Я попробовал это с summaries, но это не сработало:

new <- df %>%
  group_by(Product)%>%
summarise((Value > 10) = sum(Value)) %>%
  ungroup()

3 ответа

Решение

Мы можем использовать dplyr::row_number эффективно ранжировать наблюдения после использования arrange упорядочить данные по Value, Затем мы увеличиваем Product столбец, так что любые значения, которые не входят в топ-9, закодированы как Rest, Наконец, мы группируем по обновленным Product и взять сумму, используя summarise

dat %>%
    arrange(desc(Value)) %>%
    mutate(RowNum = row_number(),
           Product = ifelse(RowNum <= 9, Product, 'Rest')) %>%
    group_by(Product) %>%
    summarise(Value = sum(Value))

# A tibble: 10 × 2
   Product Value
     <chr> <int>
1        d    10
2        e    15
3        i    50
4        j    20
5        k    35
6        l    25
7        o    30
8        q    40
9     Rest    46
10       t    40

данные

dat <- structure(list(Product = c("a", "b", "c", "d", "e", "f", "g", 
"h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t"
), Value = c(2L, 4L, 3L, 10L, 15L, 5L, 6L, 4L, 50L, 20L, 35L, 
25L, 4L, 6L, 30L, 4L, 40L, 5L, 3L, 40L)), .Names = c("Product", 
"Value"), class = "data.frame", row.names = c(NA, -20L))

Еще один способ с dplyr будет создавать результат с do, Код становится немного трудно читать, так как вам нужно использовать .$, но вы можете избежать ifelse/if_else, После оформления заказа ValueВы можете создать два вектора. Один с первыми девятью названиями продуктов и "отдых". Другой с первыми девятью значениями и суммой значений других значений. Вы напрямую создаете фрейм данных, используя do,

df %>%
arrange(desc(Value)) %>%
do(data.frame(Product = c(as.character(.$Product[1:9]), "Rest"),
              Value = c(.$Value[1:9], sum(.$Value[10:length(.$Value)]))))

#   Product Value
#1        i    50
#2        q    40
#3        t    40
#4        k    35
#5        o    30
#6        l    25
#7        j    20
#8        e    15
#9        d    10
#10    Rest    46

Вот один из вариантов использования data.table

library(data.table)
setDT(df)[, i1 := .I][order(desc(Value))
          ][-(seq_len(9)), Product := 'rest'
           ][, .(Value = sum(Value), i1=i1[1L]), Product
           ][order(Product=='rest', i1)][, i1 := NULL][]
#    Product Value
#1:       d    10
#2:       e    15
#3:       i    50
#4:       j    20
#5:       k    35
#6:       l    25
#7:       o    30
#8:       q    40
#9:       t    40
#10:   rest    46
Другие вопросы по тегам