【问题标题】:Subsetting by summing number of values in clustered data in R [duplicate]通过对 R 中聚类数据中的值的数量求和来进行子集 [重复]
【发布时间】:2015-05-31 16:37:57
【问题描述】:

我正在尝试解决数据格式问题。 我有一个数据框,其中变量被划分为学校和学生。例如:

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, ]

有没有办法创建一个额外的变量(学校规模)来保存每所学校的学生人数(该特定学校独有)? 如果我可以有这样的变量,我可以根据它进行子集化。

【问题讨论】:

  • 每一行是唯一的学生,还是有时您有多行与同一个学生?如果是这样,一种方法是(假设Students 是一个因素)df[with(df, ave(as.numeric(Students), Schools, FUN = function(x) length(x) &gt; 1)), ]。这将返回子集而不创建额外的列
  • 好问题,每行只有一个学生

标签: r subset multi-level


【解决方案1】:

使用data.table

library(data.table)#v1.9.5+
setDT(df)[, if(.N > 1) .SD, Schools]

还使用@flodel 在重复问题中的回答作为灵感:

dat[table(Students)[Students] >2]

如果条件基于unique 每个“学校”的“学生”数量的长度

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)

【讨论】:

  • 谢谢你的作品,包括我没有在编辑中添加的 dplyr 的使用
【解决方案2】:

这成功了:

 dat[ with(dat, as.numeric(ave(as.character(Students), Schools, FUN=length))) >2, ]

第一个测试用例只有你的例子,但我注意到如果没有 ave 函数周围的 as.numeric,我会得到一个字符结果,并担心它可能无法通过 "120" > "20" 的测试这将返回 FALSE。添加 as.numeric 解决了这个问题。对于 Arenbergs 对可能重复学生姓名的担忧,可以肯定地将 unique() 包裹在 ave-FUN 内的长度参数周围。

这将创建分类变量:

dat$snum <-with(dat, as.numeric( ave( as.character(Students), Schools, FUN=length))) 

【讨论】:

  • 谢谢,效果很好,我想知道是否有一种方法可以创建一个变量“学校规模”,我可以将其用于子集
  • 使用ave 可以解决这个问题(如果你问过这个问题。)因为没有被问到,创建一个新变量会以一种未被请求的方式更改数据。
【解决方案3】:

使用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

【讨论】:

  • 谢谢你,不幸的是,它没有子集
  • 我没有检查你问题中的编辑,我相应地改变了我的答案。
  • 是的,谢谢
猜你喜欢
  • 2016-02-12
  • 2020-08-31
  • 2017-03-24
  • 1970-01-01
  • 2021-10-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多