折叠数据表中的冗余行

时间:2018-10-11 13:03:38

标签: r data.table

我有一个数据表,格式为:

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

我只想对Col1中的每个类别显示最高结果,然后折叠所有其他结果,并在Col2中显示它们的总和。它应该看起来像这样:

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
}

这可行,但是我试图缩短一个非常大的数据表,所以要花很多时间。

有没有更好的方法来解决这个问题?

谢谢。

更新:实际上,我的过程有点复杂。我认为在掌握了基础知识之后我将能够自己开发它,但是似乎我需要进一步的帮助。我想在Col1中显示5个最高值,然后折叠其他值,但是Col1中的某些条目没有5个值;在这种情况下,应显示所有条目,并且不应添加“其他”行。

5 个答案:

答案 0 :(得分:2)

此处,数据根据Col1by = Col1)的值分为几组。 .N是给定组中最后一行的索引,因此c(Col2[.N], sum(Col2) - Col2[.N]))给出Col2的最后一个值,而Col2的总和减去最后一个值。新创建的变量被.()包围,因为在使用data.table时,.()list()函数的别名,创建的列需要放在列表中。

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

答案 1 :(得分:1)

如果只是显示内容,可以使用“表”包:

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

答案 2 :(得分:0)

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

答案 3 :(得分:0)

我做到了!我做了一个新的 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]

呜呜呜!

答案 4 :(得分: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