R 按计数分组
我有一个数据框R 按计数分组,r,count,dplyr,subset,R,Count,Dplyr,Subset,我有一个数据框 library(dplyr) ID <- c(1,1,1,1,2,2,3,3,3,3,4,4,5) Score <- c(20,22,34,56,78,98,56,43,45,33,24,54,22) Quarter <- c("Q1","Q2","Q3","Q4","Q1","Q2","Q1","Q2","Q3","Q4","Q1","Q2","Q1") df <- data.frame(ID,Score,Quarter) 但它并没有起作用,我们将非
library(dplyr)
ID <- c(1,1,1,1,2,2,3,3,3,3,4,4,5)
Score <- c(20,22,34,56,78,98,56,43,45,33,24,54,22)
Quarter <- c("Q1","Q2","Q3","Q4","Q1","Q2","Q1","Q2","Q3","Q4","Q1","Q2","Q1")
df <- data.frame(ID,Score,Quarter)
但它并没有起作用,我们将非常感谢它的指导。
谢谢我们可以做的一种方法是使用n_distinct为每个ID获取唯一的值,并过滤包含所有4个值的组
library(dplyr)
df %>%
group_by(ID) %>%
filter(n_distinct(Quarter) == 4)
# ID Score Quarter
# <dbl> <dbl> <fct>
#1 1.00 20.0 Q1
#2 1.00 22.0 Q2
#3 1.00 34.0 Q3
#4 1.00 56.0 Q4
#5 3.00 56.0 Q1
#6 3.00 43.0 Q2
#7 3.00 45.0 Q3
#8 3.00 33.0 Q4
下面是另一个使用table、rowSums和%的base R方法。我们通过表获得“ID”、“Quarter”列的频率计数,将其转换为逻辑矩阵,其中0值为真,其他值为假!表…,获取行和行和,转换为逻辑向量,获取为TRUE的元素的名称,并使用%in%创建与ID的比较以子集数据集
subset(df, ID %in% names(which(!rowSums(!table(df[c(1,3)])))))
# ID Score Quarter
#1 1 20 Q1
#2 1 22 Q2
#3 1 34 Q3
#4 1 56 Q4
#7 3 56 Q1
#8 3 43 Q2
#9 3 45 Q3
#10 3 33 Q4
我想我也能做到:
df[df$ID %in% names(table(df$ID))[table(df$ID)==4],]
它只使用ID中的计数就可以得到所需的结果。这里有一些替代方法。最后三个是基本解决方案 1是一个SQL解决方案,它创建一个单列数据帧df0,其中只有那些ID有4个四分之一,然后将这些ID连接到df,从而消除所有其他ID 2是一个dplyr解决方案,它过滤只保留4行的组 3是一个data.table解决方案,它为那些具有4行的ID组返回行,为其他组返回NULL。这会消除其他组的影响 4是一个zoo解决方案,它将df转换为一个宽格式的zoo对象,顶部带有四分之一,ID作为时间索引。然后,它将删除任何具有NA的行,并使用fortify.zoo将其重塑回原始行,同时将其重新排序回已排序的顺序。如果行顺序无关紧要,则可以省略解决方案的最后一行。有趣的是,它没有使用数字4的知识 5是一个基本解决方案,它将df拆分为一个数据帧列表,每个ID一个,然后使用过滤器提取具有4行的数据帧。最后,它把一切都重新组合起来 6是一个基本解决方案,它创建一个向量,每行df有一个元素,包含行数,包括该行中ID为的当前行。然后使用子集将df减少到向量等于4的行 7是一个基本解决方案,它将df拆分为一个数据帧列表,每个ID一个,然后使用Reduce对其进行迭代,如果它有4行,则将当前数据帧附加到我们目前拥有的数据帧,如果没有,则仅保留我们目前拥有的数据帧
# 1
library(sqldf)
sqldf("with df0 as (
select ID from df group by ID having count(*) = 4
)
select * from df join df0 using (ID)")
# 2
library(dplyr)
df %>% group_by(ID) %>% filter(n() == 4) %>% ungroup
# 3
library(data.table)
as.data.table(df)[, if (nrow(.SD) == 4) .SD, by = ID]
# 4
library(zoo)
z <- read.zoo(df, split = "Quarter")
df2 <- fortify.zoo(na.omit(z), melt = TRUE, names = names(df)[c(1, 3:2)])
df2 <- df2[order(df2$ID, df2$Quarter), ]
# 5
do.call("rbind", Filter(function(x) nrow(x) == 4, split(df, df$ID)))
# 6
subset(df, ave(ID, ID, FUN = length) == 4)
# 7
Reduce(function(x, y) if (nrow(y) == 4) rbind(x, y) else x, split(df, df$ID))
df[df$ID %in% names(table(df$ID))[table(df$ID)==4],]
# 1
library(sqldf)
sqldf("with df0 as (
select ID from df group by ID having count(*) = 4
)
select * from df join df0 using (ID)")
# 2
library(dplyr)
df %>% group_by(ID) %>% filter(n() == 4) %>% ungroup
# 3
library(data.table)
as.data.table(df)[, if (nrow(.SD) == 4) .SD, by = ID]
# 4
library(zoo)
z <- read.zoo(df, split = "Quarter")
df2 <- fortify.zoo(na.omit(z), melt = TRUE, names = names(df)[c(1, 3:2)])
df2 <- df2[order(df2$ID, df2$Quarter), ]
# 5
do.call("rbind", Filter(function(x) nrow(x) == 4, split(df, df$ID)))
# 6
subset(df, ave(ID, ID, FUN = length) == 4)
# 7
Reduce(function(x, y) if (nrow(y) == 4) rbind(x, y) else x, split(df, df$ID))