Свернуть избыточные строки в таблице данных

У меня есть таблица данных в формате:

myTable <- data.table(Col1 = c("A", "A", "A", "B", "B", "B"), Col2 = 1:6)
print(myTable)

   Col1 Col2
1:    A    1
2:    A    2
3:    A    3
4:    B    4
5:    B    5
6:    B    6

Я хочу показать только наивысший результат для каждой категории в столбце 1, затем свернуть все остальные и представить их сумму в столбце 2. Должно получиться так:

print(myTable)

       Col1 Col2
1:        A    3
2:   Others    3
3:        B    6
4:   Others    9

Мне удалось это сделать с помощью следующего кода:

unique <- unique(myTable$Col1)                                  # unique values in Col1
myTable2 <- data.table()                                        # empty data table to populate
for(each in unique){
    temp <- myTable[Col1 == each, ]                             # filter myTable for unique Col1 values
    temp <- temp[order(-Col2)]                                  # order filtered table increasingly
    sumCol2 <- sum(temp$Col2)                                   # sum of values in filtered Col2
    temp <- temp[1, ] # retain only first element
    remSum <- sumCol2 - sum(temp$Col2)                          # remaining sum in Col2 (without first element)
    temp <- rbindlist(list(temp, data.table("Others", remSum))) # rbind first element and remaining elements
    myTable2 <- rbindlist(list(myTable2, temp))                 # populate data table from beginning
}

Это работает, но я пытаюсь сократить очень большую таблицу данных, поэтому на это уходит вечность.

Есть ли лучший способ подойти к этому?

Спасибо.

ОБНОВИТЬ: На самом деле моя процедура немного сложнее. Я подумал, что смогу разработать его сам после того, как освоу основы, но, похоже, вместо этого мне понадобится дополнительная помощь. Я хочу отобразить 5 самых высоких значений в столбце Col1 и свернуть остальные, но некоторые записи в столбце Col1 не имеют 5 значений; в этом случае должны отображаться все записи, и не следует добавлять строку «Другие».

"I want show only the first result for each category in Col1" похоже вы хотите показать последнее.
Andre Elrico 11.10.2018 15:14

Собственно я имел ввиду высшее значение, поправил, спасибо.

Denny Ceccon 11.10.2018 16:31

ну .... это все меняет. Я обновил свое решение.

Andre Elrico 11.10.2018 16:42

Это плохой формат для использования в анализе, поскольку вы больше не можете распознать первые «Другие» как связанные с A, кроме как на основе текущей сортировки. В любом случае, повторно ваше «обновление», может быть, myTable[order(-Col2), lapply(.SD, sum), by=.(Col1, r = as.character(replace(r <- rowid(Col1), r > 5, "other")))], хотя вам нужно будет предоставить соответствующий пример, чтобы мы могли подтвердить ... Поскольку было опубликовано так много ответов, вы можете опубликовать новый вопрос, если не можете его понять.

Frank 11.10.2018 17:11
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
4
131
5

Ответы 5

Здесь данные разбиты на группы в соответствии со значением Col1 (by = Col1). .N - это индекс последней строки в данной группе, поэтому c(Col2[.N], sum(Col2) - Col2[.N])) дает последнее значение Col2 и сумму Col2 за вычетом последнего значения. Вновь созданные переменные окружены .(), потому что .() является псевдонимом для функции list() при использовании data.table, а созданные столбцы должны быть в списке.

library(data.table)
setDT(df)

df[, .(Col1 = c(Col1, 'Others'),
       Col2 = c(Col2[.N], sum(Col2) - Col2[.N]))
  , by = Col1][, -1]
#      Col1 Col2
# 1:      A    3
# 2: Others    3
# 3:      B    6
# 4: Others    9

Превосходно! Не могли бы вы пояснить синтаксис? Хотя мне это нравится, я все еще новичок в пакете data.table. На самом деле моя процедура немного сложнее: я хочу сохранить 5 верхних записей, но некоторые значения в Col1 не имеют 5 записей; в этих случаях следует сохранить все записи и не включать строку «Прочие».

Denny Ceccon 11.10.2018 16:01

Если бы это просто вопрос отображения вещей, вы могли бы пакеты 'table':

others <- function(x) sum(x)-last(x)
df %>% tabular(Col1*(last+others) ~ Col2, .)

# Col1        Col2
# A    last   3   
#      others 3   
# B    last   6   
#      others 9
do.call(
    rbind, lapply(split(myTable, factor(myTable$Col1)), function(x) rbind(x[which.max(x$Col2),], list("Other", sum(x$Col2[-which.max(x$Col2)]))))
)

#    Col1 Col2
#1:     A    3
#2: Other    3
#3:     B    6
#4: Other    9

Я это сделал! Я сделал новый myTable для иллюстрации. Я хочу сохранить только 4 самых высоких значения по категориям и свернуть остальные.

set.seeed(123)
myTable <- data.table(Col1 = c(rep("A", 3), rep("B", 5), rep("C", 4)), Col2 = sample(1:12, 12))
print(myTable)

    Col1 Col2
 1:    A    8
 2:    A    5
 3:    A    2
 4:    B    7
 5:    B   10
 6:    B    9
 7:    B   12
 8:    B   11
 9:    C    4
10:    C    6
11:    C    3
12:    C    1

# set key to Col2, it will sort it increasingly
setkey(myTable, Col2)

# if there are more than 4 entries by Col1 category, will return all information, otherwise will return 4 entries completing with NA
myTable <- myTable[,.(Col2 = Col2[1:max(c(4, .N))]) , by = Col1]

# will print in Col1: 4 entries of Col1 category, then "Other"
# will print in Col2: 4 last entries of Col2 in that category, then the remaining sum 
myTable <- myTable[, .(Col1 = c(rep(Col1, 4), "Other"), Col2 = c(Col2[.N-3:0], sum(Col2) - sum(Col2[.N-3:0]))), by = Col1]

# removes rows with NA inserted in first step
myTable <- na.omit(myTable)

# removes rows where Col2 = 0, inserted because that Col1 category had exactly 4    entries
myTable <- myTable[Col2 != 0]

Ооооооо!

Вот базовое решение R и эквивалент dplyr:

res <- aggregate(Col2 ~.,transform(
  myTable, Col0 = replace(Col1,duplicated(Col1,fromLast = TRUE), "Other")), sum)
res[order(res$Col1),-1]
#    Col0 Col2
# 1     A    3
# 3 Other    3
# 2     B    6
# 4 Other    9

myTable %>%
  group_by(Col0= Col1, Col1= replace(Col1,duplicated(Col1,fromLast = TRUE),"Other")) %>%
  summarize_at("Col2",sum) %>%
  ungroup %>%
  select(-1)
# # A tibble: 4 x 2
#   Col1   Col2
#   <chr> <int>
# 1 A         3
# 2 Other     3
# 3 B         6
# 4 Other     9

Другие вопросы по теме