通过对 R 中的聚类数据中的值数求和来进行子集化
Subsetting by summing number of values in clustered data in R
我正在尝试解决数据格式问题。
我有一个数据框,其中变量分为学校和学生。例如:
Schools Students
SchoolA Student1
SchoolA Student2
SchoolA Student3
SchoolB Student4
SchoolB Student5
SchoolC Student6
我想创建我的数据集的一个子集,只保留学生人数超过 X(例如,至少 2 人)的学校。
在 R 中有一种简单的方法可以做到这一点吗?
我怎样才能用每所学校的学生人数创建一个额外的变量(列),以便我可以基于它进行子集化?
预先感谢您的帮助!
编辑 - - - - - -
非常感谢您的回复。我创建了一个示例以供将来参考。
# creating a dataset
Schools <- c('SchA','SchA','SchA','SchA','SchA',
'SchB','SchB','SchB','SchB','SchB','SchB',
'SchC','SchC')
Students <- c('st1','st2','st3','st4','st5','st6',
'st7','st8','st9', 'st10', 'st11', 'st12', 'st13')
df <- data.frame(Schools, Students)
install.packages('data.table')
library(data.table)
setDT(df)[, if(.N > 4) .SD, Schools] # only schools A & B
df[ with(df, as.numeric(ave(as.character(Students), Schools, FUN=length))) >2, ]
有没有办法创建一个附加变量(学校规模)来保存每所学校的学生人数(特定学校独有)?
如果我可以有这样的变量,我可以基于它进行子集化。
这成功了:
dat[ with(dat, as.numeric(ave(as.character(Students), Schools, FUN=length))) >2, ]
第一个测试用例只有你的例子,但我注意到 ave
函数周围没有 as.numeric,我得到的是一个字符结果,担心它可能无法通过 " 120" > "20" 将返回 FALSE。添加 as.numeric 解决了这个问题。对于 Arenberg 对学生姓名可能重复的担忧,我们可以肯定地将 unique()
包裹在 ave-FUN 中的长度参数周围。
这将创建分类变量:
dat$snum <-with(dat, as.numeric( ave( as.character(Students), Schools, FUN=length)))
使用data.table
library(data.table)#v1.9.5+
setDT(df)[, if(.N > 1) .SD, Schools]
也使用@flodel 在重复问题中的回答作为灵感:
dat[table(Students)[Students] >2]
如果条件是根据长度unique
个'Students'个'Schools'
setDT(df)[, if(uniqueN(Students) > 1) .SD, Schools]
使用 dplyr
的类似方法
library(dplyr)
df %>%
group_by(Schools) %>%
filter(n_distinct(Students) > 1)
#or depending on the condition
#filter(n() > 1)
更新
如果您需要在子集化之前创建列(使用新数据集)
setDT(df)[, no.of.students := .N, Schools][, if(.N > 4) .SD, Schools]
# Schools Students no.of.students
# 1: SchA st1 5
# 2: SchA st2 5
# 3: SchA st3 5
# 4: SchA st4 5
# 5: SchA st5 5
# 6: SchB st6 6
# 7: SchB st7 6
# 8: SchB st8 6
# 9: SchB st9 6
#10: SchB st10 6
#11: SchB st11 6
df %>%
group_by(Schools) %>%
mutate(no.of.students=n()) %>%
filter(n()>4)
使用lapply()
student.count = 2 # depends on your choice
out = do.call(rbind,
lapply(split(df, f = df$Schools),
function(x){
x$no.of.students = length(x$Students);
x = subset(x, no.of.students > student.count)
}))
#> out
# Schools Students no.of.students
#SchA.1 SchA st1 5
#SchA.2 SchA st2 5
#SchA.3 SchA st3 5
#SchA.4 SchA st4 5
#SchA.5 SchA st5 5
#SchB.6 SchB st6 6
#SchB.7 SchB st7 6
#SchB.8 SchB st8 6
#SchB.9 SchB st9 6
#SchB.10 SchB st10 6
#SchB.11 SchB st11 6
我正在尝试解决数据格式问题。 我有一个数据框,其中变量分为学校和学生。例如:
Schools Students
SchoolA Student1
SchoolA Student2
SchoolA Student3
SchoolB Student4
SchoolB Student5
SchoolC Student6
我想创建我的数据集的一个子集,只保留学生人数超过 X(例如,至少 2 人)的学校。 在 R 中有一种简单的方法可以做到这一点吗? 我怎样才能用每所学校的学生人数创建一个额外的变量(列),以便我可以基于它进行子集化? 预先感谢您的帮助!
编辑 - - - - - -
非常感谢您的回复。我创建了一个示例以供将来参考。
# creating a dataset
Schools <- c('SchA','SchA','SchA','SchA','SchA',
'SchB','SchB','SchB','SchB','SchB','SchB',
'SchC','SchC')
Students <- c('st1','st2','st3','st4','st5','st6',
'st7','st8','st9', 'st10', 'st11', 'st12', 'st13')
df <- data.frame(Schools, Students)
install.packages('data.table')
library(data.table)
setDT(df)[, if(.N > 4) .SD, Schools] # only schools A & B
df[ with(df, as.numeric(ave(as.character(Students), Schools, FUN=length))) >2, ]
有没有办法创建一个附加变量(学校规模)来保存每所学校的学生人数(特定学校独有)? 如果我可以有这样的变量,我可以基于它进行子集化。
这成功了:
dat[ with(dat, as.numeric(ave(as.character(Students), Schools, FUN=length))) >2, ]
第一个测试用例只有你的例子,但我注意到 ave
函数周围没有 as.numeric,我得到的是一个字符结果,担心它可能无法通过 " 120" > "20" 将返回 FALSE。添加 as.numeric 解决了这个问题。对于 Arenberg 对学生姓名可能重复的担忧,我们可以肯定地将 unique()
包裹在 ave-FUN 中的长度参数周围。
这将创建分类变量:
dat$snum <-with(dat, as.numeric( ave( as.character(Students), Schools, FUN=length)))
使用data.table
library(data.table)#v1.9.5+
setDT(df)[, if(.N > 1) .SD, Schools]
也使用@flodel 在重复问题中的回答作为灵感:
dat[table(Students)[Students] >2]
如果条件是根据长度unique
个'Students'个'Schools'
setDT(df)[, if(uniqueN(Students) > 1) .SD, Schools]
使用 dplyr
library(dplyr)
df %>%
group_by(Schools) %>%
filter(n_distinct(Students) > 1)
#or depending on the condition
#filter(n() > 1)
更新
如果您需要在子集化之前创建列(使用新数据集)
setDT(df)[, no.of.students := .N, Schools][, if(.N > 4) .SD, Schools]
# Schools Students no.of.students
# 1: SchA st1 5
# 2: SchA st2 5
# 3: SchA st3 5
# 4: SchA st4 5
# 5: SchA st5 5
# 6: SchB st6 6
# 7: SchB st7 6
# 8: SchB st8 6
# 9: SchB st9 6
#10: SchB st10 6
#11: SchB st11 6
df %>%
group_by(Schools) %>%
mutate(no.of.students=n()) %>%
filter(n()>4)
使用lapply()
student.count = 2 # depends on your choice
out = do.call(rbind,
lapply(split(df, f = df$Schools),
function(x){
x$no.of.students = length(x$Students);
x = subset(x, no.of.students > student.count)
}))
#> out
# Schools Students no.of.students
#SchA.1 SchA st1 5
#SchA.2 SchA st2 5
#SchA.3 SchA st3 5
#SchA.4 SchA st4 5
#SchA.5 SchA st5 5
#SchB.6 SchB st6 6
#SchB.7 SchB st7 6
#SchB.8 SchB st8 6
#SchB.9 SchB st9 6
#SchB.10 SchB st10 6
#SchB.11 SchB st11 6