【问题标题】:R: summarise multiple column (numeric, character) and remove NAsR:汇总多列(数字、字符)并删除 NA
【发布时间】:2016-04-23 18:20:13
【问题描述】:

我有一个包含许多列 (~50) 的 data.frame。其中一些是字符,一些是数字,其中 3 个用于分组。

我需要:

  • 从数字列中删除 NA
  • 计算每个数字列的平均值
  • 提取字符列的第一个元素

假设我们正在使用修改后的虹膜数据,如下所示:

data(iris)
iris$year <- rep(c(2000,3000),each=25) ## for grouping
iris$color <- rep(c("red","green","blue"),each=50) ## character column
iris[1,] <- NA ## introducing NAs

我总共有大约 50 列,数字和字符混合在一起。我一直在尝试类似的东西:

giris <- group_by(iris, Species, year)
cls <- unlist(sapply(giris, class)) ## find out classes
action <- ifelse(cls == "numeric", "mean", "first")
action <- paste(action)
summarise_each(giris, action)

我得到的是组中所有列的含义,然后是相应组中具有第一个值的列。而且 NA 没有得到处理……这不是我所寻求的……

帮助任何人?

【问题讨论】:

    标签: r dplyr na.rm


    【解决方案1】:

    您可以在summarise_each 的funs 中使用if/else 试试这个:

    iris %>% 
      group_by(Species, year) %>% 
      summarise_each(funs(if(is.numeric(.)) mean(., na.rm = TRUE) else first(.)))
    

    由于您在分组列中也有一些 NA,您可以添加 filter 语句:

    iris %>% 
      filter(!is.na(Species) & !is.na(year)) %>% 
      group_by(Species, year) %>% 
      summarise_each(funs(if(is.numeric(.)) mean(., na.rm = TRUE) else first(.)))
    #Source: local data frame [6 x 7]
    #Groups: Species [?]
    #
    #     Species  year Sepal.Length Sepal.Width Petal.Length Petal.Width color
    #      (fctr) (dbl)        (dbl)       (dbl)        (dbl)       (dbl) (chr)
    #1     setosa  2000        5.025    3.479167       1.4625       0.250   red
    #2     setosa  3000        4.984    3.376000       1.4640       0.244   red
    #3 versicolor  2000        6.012    2.776000       4.3120       1.344 green
    #4 versicolor  3000        5.860    2.764000       4.2080       1.308 green
    #5  virginica  2000        6.576    2.928000       5.6400       2.044  blue
    #6  virginica  3000        6.600    3.020000       5.4640       2.008  blue
    

    为避免颜色列(或任何非数字列)中可能出现 NA,您可以将其修改为 first(na.omit(.))。


    你也可以试试data.table:

    library(data.table)
    setDT(iris)
    iris[!is.na(Species) & !is.na(year), lapply(.SD, function(x) {
         if(is.numeric(x)) mean(x, na.rm = TRUE) else x[!is.na(x)][1L]}), 
         by = list(Species, year)]
    #      Species year Sepal.Length Sepal.Width Petal.Length Petal.Width color
    #1:     setosa 2000        5.025    3.479167       1.4625       0.250   red
    #2:     setosa 3000        4.984    3.376000       1.4640       0.244   red
    #3: versicolor 2000        6.012    2.776000       4.3120       1.344 green
    #4: versicolor 3000        5.860    2.764000       4.2080       1.308 green
    #5:  virginica 2000        6.576    2.928000       5.6400       2.044  blue
    #6:  virginica 3000        6.600    3.020000       5.4640       2.008  blue
    

    【讨论】:

    • 我认为您可能想在group_by 上方添加na.omit(),但这是问题的要点。
    • @JasonAizkalns,我不这么认为——这可能会删除许多应该保留的行。但我同意filter(!is.na(Species) &amp; !is.na(year)) 是有意义的
    • 这是一个非常好的和(最重要的)工作解决方案,它还可以让我们一睹 summarise_each 的幕后工作。我真的非常感谢它,Doncendo :-)。同时,您认为有没有办法加快速度?
    • @rpl,很高兴它对你有用。我认为这段代码在 dplyr 中不会有显着的性能。您可以尝试将first(na.omit(.)) 替换为.[!is.na(.)][1L]。我还可以使用 data.table 添加类似的方法,这可能会更快。
    【解决方案2】:

    我试试看:

    1。 对于您提到的第一点,我会执行以下操作(第二点不是必需的):

    na.omit(iris[ , which(sapply(iris, class) == "numeric")])
    

    要分隔 numeric 或 character 的列,我使用以下内容:

    iris[ , which(sapply(iris, class) == "numeric")]
    iris[ , which(sapply(iris, class) == "character")]
    

    2。 第二个任务我把上面这行和colMeans结合起来:

    colMeans(iris[ , which(sapply(iris, class) == "numeric")], na.rm = TRUE)
    

    3。 要提取字符列的第一个元素,您可以简单地执行以下操作:

    iris[1, which(sapply(iris, class) == "character")]
    

    在提到的虹膜数据的情况下,第一行完全是 NA,甚至是字符列,所以我会迭代找到第一个非 NA 行

    k <- 1
    while(any(is.na(FirstCharacterElement <- iris[k, which(sapply(iris, class) == "character")]))){
      k <- k + 1
    }
    

    注意类因子(在 iris 数据的情况下,它会分解代码,其中 Species 列属于类因子并且您可能希望它是一个字符列。您可以使用 sapply(iris, class) 进行检查并更改它与例如

    iris$Species <- as.character(iris$Species) #or with similar column names
    

    当您读入数据时,您可以提及函数read.table、read.csv 或类似函数的参数stringsAsFactors = FALSE。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-22
      • 2021-03-14
      • 1970-01-01
      • 2021-05-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多