按因子列聚合混合数据

时间:2016-05-29 12:07:11

标签: r dataframe group-by aggregate grouping

在过去的一周里,我一直在尝试聚合我的数据集,该数据集包含不同月份的不同重量测量值,并伴随着R中的大量背景变量。

我已经阅读了很多关于这个主题的不同问题(例如R aggregate data by defining groupingHow to aggregate count of unique values of categorical variables in R),但它们似乎只能用于一种类型的数据,或者只对一列感兴趣。具体来说,问题Recoding categorical variables to the most common value处理几乎完全相同的问题,但建议的答案仅解决了分类数据的问题,它也不包括数字数据。我的数据包括两个因素(分类和序数)和数字数据。

可重现的例子是:

IDnumber <- c("1", "1", "1", "2", "2", "3", "3", "3")
Gender <- c("Male", "Male", "Male", "Female", "Female", "Female", "Female",  "Female")
Weight <- c(80, 82, 82, 70, 66, 54, 50, 52)
LikesSoda <- c("Yes", "No", "No", "Yes", "Yes", "Yes", "Yes", NA)
df = data.frame(IDnumber, Gender, Weight, LikesSoda)

我的输出数据帧将取每个数值列的平均值,并且是每个因子列的最常见因子。在示例中,这将如下所示:

IDnumber <- c("1", "2", "3")
Gender <- c("Male", "Female", "Female")
Weight <- c(81.5, 78, 52)
LikesSoda <- c("No", "Yes", "Yes")
output = data.frame(IDnumber, Gender, Weight, LikesSoda)

到目前为止,我已经尝试将数据帧拆分为因子数据帧和数字数据帧,并使用两个具有不同功能的聚合(对于数字的意思,但我无法找到分类数据的工作函数) )。另一个选项是使用dplyr df &>& group_by(IDnumber) %>% summarise( transformation for each variable )代码,但这需要我指定如何手动处理每个列。由于我有超过2500列,这似乎不是一个可行的解决方案。

1 个答案:

答案 0 :(得分:2)

您可以编写自己的函数,然后使用lapply。首先,编写一个函数来查找因子变量中最常见的级别

getmode <- function(v) {
  levels(v)[which.max(table(v))]
}

然后编写一个函数,根据传递给它的变量类型返回均值或模式

my_summary <- function(x, id, ...){
  if (is.numeric(x)) {
    return(tapply(x, id, mean))
  }  
  if (is.factor(x)) {
    return(tapply(x, id, getmode))
  }  
}

最后,使用lapply计算摘要

data.frame(lapply(df, my_summary, id = df$IDnumber))
  IDnumber Gender   Weight LikesSoda
1        1   Male 81.33333        No
2        2 Female 68.00000       Yes
3        3 Female 52.00000       Yes

如果一个因子中有两个或更多个级别具有相同的最大频率,则which.max将返回第一个级别。我从你的评论中了解到你只想知道它们中有多少,所以一个选项可能是略微修改getmode函数,所以当有一个平局时它会在级别上添加一个星号:

getmode <- function(v) {
  tab <- table(v)
  if (sum(tab %in% max(tab)) > 1)  return(paste(levels(v)[which.max(tab)], '*'))
  levels(v)[which.max(tab)]
}

(更改样本数据,因此有一位女性和一位男性ID号码==&#34; 2&#34;)

data.frame(lapply(df, my_summary, id = df$IDnumber))

  IDnumber   Gender   Weight LikesSoda
1        1     Male 81.33333        No
2        2 Female * 68.00000       Yes
3        3   Female 52.00000       Yes

我担心这会是一个混乱的解决方案,但是如果你只是想知道这个问题的常见程度,也许这对你来说已经足够了需要。