如何对数据进行分组,并限制 R 中的组大小
How to group data, with restrictions on group size in R
给定一个数据框,我可以将行分组到规定的 属性 下,对它们进行计数以了解组的大小,并为它们分配唯一的 ID 号。但我真正需要的是执行此过程,以便在以下三种情况下限制组大小:
- 如果 size modulo 3 = 0,则分成较小的组,所有的 size 都是 3,
- 如果尺寸模 3 = 1,则分成尺寸为 3 的较小组和尺寸为 2 的两组。
- 如果尺寸模 3 = 2,则分成尺寸为 3 的较小组和尺寸为 2 的一组
因此,如果大小为 4,则创建两个组,大小均为 2;而当尺寸为 5 时,则分成两组尺寸 3 和 2。
我创建了以下最小示例。
这是起始数据。通常,它不会被排序并且可以有更多的列:
structure(
list(property = c("A", "B", "B", "C", "C", "C", "D", "D", "D", "D", "E", "E", "E", "E", "E", "F", "F", "F", "F", "F", "F", "G", "G", "G", "G", "G", "G", "G")),
class = c("tbl_df", "tbl", "data.frame"),
row.names = c(NA, -28L),
.Names = "property"
)
所需的输出将是:
structure(
list(property = c("A", "B", "B", "C", "C", "C", "D", "D", "D", "D", "E", "E", "E", "E", "E", "F", "F", "F", "F", "F", "F", "G", "G", "G", "G", "G", "G", "G"),
id = c(1, 2, 2, 3, 3, 3, 4, 4, 5, 5, 6, 6, 6, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, 11, 11, 12, 12)),
class = c("tbl_df", "tbl", "data.frame"),
row.names = c(NA, -28L),
.Names = c("property", "id")
)
组的顺序并不重要。
我首先创建一个函数,它将根据您的要求创建相同数量的组。基本上,它总是会创建三个相等数字的组,然后在最后切断那些太多的数字。在特殊情况下,最后一组的长度为 1,最后一个元素被最后一个元素替换以满足您的条件 2:
create_grp_idx <- function(x) {
n <- length(x)
m <- n %/% 3 + 1
idx <- rep(1:m, each = 3)[1:n]
if (n %% 3 == 1 && n > 1) idx[n-1] <- idx[n]
return (idx)
}
现在我使用 dplyr
按 property
对数据进行分组,然后将 create_grp_idx()
应用于每个组,从而创建索引 n
。然后,我使用 interaction()
从 property
和新创建的索引 n
的每个组合中获取一个因子。由于您在示例中使用了数字,因此我将因子转换为数字,最后删除索引为 n
.
的列
library(dplyr)
group_by(data, property) %>%
mutate(n = create_grp_idx(property)) %>%
ungroup %>%
mutate(id = as.numeric(interaction(property, n))) %>%
select(-n)
## Source: local data frame [28 x 2]
##
## property id
## (chr) (dbl)
## 1 A 1
## 2 B 2
## 3 B 2
## 4 C 3
## 5 C 3
## 6 C 3
## 7 D 4
## 8 D 4
## 9 D 11
## 10 D 11
## .. ... ...
这并没有完全给出您给出的示例输出,但是既然您说组的顺序无关紧要,我假设这就是您想要的结果。
给定一个数据框,我可以将行分组到规定的 属性 下,对它们进行计数以了解组的大小,并为它们分配唯一的 ID 号。但我真正需要的是执行此过程,以便在以下三种情况下限制组大小:
- 如果 size modulo 3 = 0,则分成较小的组,所有的 size 都是 3,
- 如果尺寸模 3 = 1,则分成尺寸为 3 的较小组和尺寸为 2 的两组。
- 如果尺寸模 3 = 2,则分成尺寸为 3 的较小组和尺寸为 2 的一组
因此,如果大小为 4,则创建两个组,大小均为 2;而当尺寸为 5 时,则分成两组尺寸 3 和 2。
我创建了以下最小示例。
这是起始数据。通常,它不会被排序并且可以有更多的列:
structure(
list(property = c("A", "B", "B", "C", "C", "C", "D", "D", "D", "D", "E", "E", "E", "E", "E", "F", "F", "F", "F", "F", "F", "G", "G", "G", "G", "G", "G", "G")),
class = c("tbl_df", "tbl", "data.frame"),
row.names = c(NA, -28L),
.Names = "property"
)
所需的输出将是:
structure(
list(property = c("A", "B", "B", "C", "C", "C", "D", "D", "D", "D", "E", "E", "E", "E", "E", "F", "F", "F", "F", "F", "F", "G", "G", "G", "G", "G", "G", "G"),
id = c(1, 2, 2, 3, 3, 3, 4, 4, 5, 5, 6, 6, 6, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, 11, 11, 12, 12)),
class = c("tbl_df", "tbl", "data.frame"),
row.names = c(NA, -28L),
.Names = c("property", "id")
)
组的顺序并不重要。
我首先创建一个函数,它将根据您的要求创建相同数量的组。基本上,它总是会创建三个相等数字的组,然后在最后切断那些太多的数字。在特殊情况下,最后一组的长度为 1,最后一个元素被最后一个元素替换以满足您的条件 2:
create_grp_idx <- function(x) {
n <- length(x)
m <- n %/% 3 + 1
idx <- rep(1:m, each = 3)[1:n]
if (n %% 3 == 1 && n > 1) idx[n-1] <- idx[n]
return (idx)
}
现在我使用 dplyr
按 property
对数据进行分组,然后将 create_grp_idx()
应用于每个组,从而创建索引 n
。然后,我使用 interaction()
从 property
和新创建的索引 n
的每个组合中获取一个因子。由于您在示例中使用了数字,因此我将因子转换为数字,最后删除索引为 n
.
library(dplyr)
group_by(data, property) %>%
mutate(n = create_grp_idx(property)) %>%
ungroup %>%
mutate(id = as.numeric(interaction(property, n))) %>%
select(-n)
## Source: local data frame [28 x 2]
##
## property id
## (chr) (dbl)
## 1 A 1
## 2 B 2
## 3 B 2
## 4 C 3
## 5 C 3
## 6 C 3
## 7 D 4
## 8 D 4
## 9 D 11
## 10 D 11
## .. ... ...
这并没有完全给出您给出的示例输出,但是既然您说组的顺序无关紧要,我假设这就是您想要的结果。