首页 > 解决方案 > 使用 R 根据重复记录对数据进行分组

问题描述

我有一个包含重复记录/常见记录的数据集。它看起来像这样:

| Vendor | Buyer | Amount |
|--------|:-----:|-------:|
| A      |   P   |    100 |
| B      |   P   |    150 |
| C      |   Q   |    300 |
| A      | P     | 290    |

我需要将类似的记录组合在一起,但我不想总结我的数量。我想单独表示金额值。输出应该是这样的:

| Vendor | Buyer | Amount |
|--------|:-----:|-------:|
| A      |   P   |    100 |
| A      |   P   |    290 |
|        |       |        |
| B      | P     | 150    |
|        |       |        |
| C      | Q     | 300    |

我曾想过使用 split(),但由于我的原始数据有太多记录,因此 split 函数会创建太多列表,并且从它们创建新数据集变得很乏味。如何使用任何其他方法实现上述输出?

编辑:让我们假设我们有一个名为 date 的附加列,数据集现在看起来像这样:

| Vendor | Buyer | Amount | Date      |
|--------|:-----:|-------:|-----------|
| A      |   P   |    100 | 3/6/2019  |
| B      |   P   |    150 | 7/6/2018  |
| C      |   Q   |    300 | 4/21/2018 |
| A      | P     | 290    | 6/5/2018  |

曾经,每个买家和供应商都被分组在一起,我需要为每个买家和供应商按升序排列日期,使其看起来像下面这样:

| Vendor | Buyer | Amount | Date      |
|--------|:-----:|-------:|-----------|
| A      |   P   |    290 | 6/5/2018  |
| A      |   P   |    100 | 3/6/2019  |
|        |       |        |           |
| B      | P     | 150    | 7/6/2018  |
|        |       |        |           |
| C      | Q     | 300    | 4/21/2018 | 

然后删除单个事务以获得仅包含的最终表

| Vendor | Buyer | Amount | Date     |
|--------|:-----:|-------:|----------|
| A      |   P   |    290 | 6/5/2018 |
| A      | P     | 100    | 3/6/2019 |

标签: rsplitgroupingmultiple-records

解决方案


在下文中,我们对数据框进行排序并添加一个组列,以便对各个组进行后续处理。例如,要在不创建大量拆分的情况下处理组DF

for(g in unique(DFout$group)) {
  DFsub <- subset(DFout, group == g)
  ... process DFsub ...
}

1) Base R对数据进行排序,然后使用cumsum非重复元素分配组列。

library(data.table)

o <- with(DF, order(Vendor, Buyer))
DFo <- DF[o, ]
DFout <- transform(DFo, group = cumsum(!duplicated(data.frame(Vendor, Buyer))))
DFout

给予:

  Vendor Buyer Amount group
1      A     P    100     1
4      A     P    290     1
2      B     P    150     2
3      C     Q    300     3

我不确定这是否是一个好主意,但如果你真的想在每个组之后添加一行 NA:

ix <- unname(unlist(tapply(DFout$group, DFout$group, function(x) c(x, NA))))
ix[!is.na(ix)] <- seq_len(nrow(DFout))
DFout[ix, ]

2)data.table 转换为data.table,设置key(对其进行排序)并用于rleid分配组号。

library(data.table)

DT <- data.table(DF)
setkey(DT, Vendor, Buyer)
DT[, group := rleid(Vendor, Buyer)]

3) sqldf另一种方法是使用SQL。这需要github 上的 RSQLite开发版本。这里dense_rank的行为与上面类似rleid

library(sqldf)

sqldf("select *, dense_rank() over (order by Vendor, Buyer) as [group]
  from DF
  order by Vendor, Buyer")

给予:

  Vendor Buyer Amount group
1      A     P    100     1
2      A     P    290     1
3      B     P    150     2
4      C     Q    300     3

笔记

DF <- structure(list(Vendor = structure(c(1L, 2L, 3L, 1L), .Label = c("A", 
"B", "C"), class = "factor"), Buyer = structure(c(1L, 1L, 2L, 
1L), .Label = c("P", "Q"), class = "factor"), Amount = c(100L, 
150L, 300L, 290L)), class = "data.frame", row.names = c(NA, -4L
))

推荐阅读