【问题标题】:counting occurence of factor levels for multiple variables and summarising results in one table计算多个变量的因子水平的出现并将结果汇​​总在一张表中
【发布时间】:2014-09-22 16:50:50
【问题描述】:

这是我在这里的第一篇文章,我对编程和 R 非常陌生。所以请原谅任何愚蠢。

我有以下数据框:

a <- data.frame("sickness1" = c(1,1,2,3,3,5,6, 4, 4, 4),
                "sickness2" = c(NA, NA, 3, 3, 4, 6, 1, 2, 5, 6),
                "sickness3" = c(NA, NA, 3, 4, 4, 6, 1, 2, 5, 6),
                "sickness4" = c(NA, NA, 6, 3, 4, 6, 1, 2, 5, 6))

每一行代表一个案例。每列都是一个有序的因子变量。我将变量转换为这样的因子(使用我在 stackoverflow 上找到的提示!):

a[] <- lapply(a, factor,
             levels = c(1:6),
             labels = c(3, 25, 50, 75, 97, 100))

我想得到以下输出:

  percent   sickness1           sickness2    sickness3       sickness4
1       3          1                1            1            2
2      25          1                1            1            1
3      50          2                1            1            2
4      75          1                2            1            3
5      97          1                1            1            1
6     100          2                2            3            1

我已经找到了一个非常冗长的解决方案:

# counting
ab <- ldply(lapply(a, count))

#getting it into the right format
ab2 <- dcast(
    data = ab,
    formula = x ~ .id,
    value.var = "freq")

# changing the name of the first column
colnames(ab2)[1] <- "percent"

#deleting row 7 cause it contains the NAs which I dont want to have
ab2 <- ab2[-7,]
ab2

有没有更快更简单的方法来做到这一点?就像以某种方式使用 ddply 一样? summary(a) 给我的输出太乱了,我不知道如何操纵它以使其看起来像我想要的那样。此外,我正在处理的真实数据要大得多,我必须多次这样做......

【问题讨论】:

  • 我想,一般来说,将此类数据放在 2 列“data.frame”(此处为 [疾病百分比])中会更有帮助;那么你可以打电话给table(mydataframe)。例如。 table(data.frame(pct = c(5,10,15,10,15,5,10,10,20,25), sickness = c(1,1,1,2,2,3,4,4,4,4)))
  • 您建议的信息丢失的形式。可能的是 3 列长的数据格式,因此值的另一列,然后它再次不适用于表(mydataframe)。为了更多地解释实际数据,每一行都是一个机构,例如一家医院,百分比是百分比范围,每个机构评估他们有多少患者患有疾病 1、疾病 2,依此类推
  • 我明白了;然而(除非内存是一个问题)像reshape(a, direction = "long", varying = list(1:4), sep = "", times = names(a)) 这样的“data.frame”可以存储必要的信息并且很容易操作。 (在这种情况下,您必须在对 table 的调用中明确声明两列。)希望我没有误解您的意思
  • 你说的是对的,如果我为机构添加另一列,我可以执行以下操作:b2
  • 刚刚发现我可以转置结果表以获得我想要的...唯一不是我想要的是它在顶部显示“变量”

标签: r


【解决方案1】:

好的,所以我发现有两种可能的解决方案:

akrun 的 Nr1:

un1 <- as.character(sort(unique(unlist(a, use.names=FALSE))))
 data.frame(percent=un1,do.call(cbind,
          lapply(a, function(x) table(factor(x, levels=un1)))))

Alexis_laz 的 Nr.2:

假设我可以轻松地使数据看起来像这样:(这只是上面的一个数据框,其中为机构添加了一个列)

a <- data.frame("institution" = c(1:10), "sickness1" = c(1,1,2,3,3,5,6, 4, 4, 4),
                "sickness2" = c(NA, NA, 3, 3, 4, 6, 1, 2, 5, 6),
                "sickness3" = c(NA, NA, 3, 4, 4, 6, 1, 2, 5, 6),
                "sickness4" = c(NA, NA, 6, 3, 4, 6, 1, 2, 5, 6))

a[-1] <- lapply(a[-1], factor,
                levels = c(1:6),
                labels = c("0 to 3%","4-25%", "25-50%", "51-75%","76-97%","97-100%"))

然后我可以将这种宽数据形式转换为长数据格式,如下所示:

b2 <- melt(a, id.vars = "institution")

然后正常的表格功能起作用:

table(b2[[3]], b2[[2]])

注意顺序很重要

非常感谢大家!

【讨论】:

    【解决方案2】:

    这主要是主题类型答案的变体。将stacktable 一起使用,如下所示:

    as.data.frame.matrix(           ## converts the output to a data.frame
      table(                        ## does the actual tabulation
        stack(                      ## stack makes your data.frame long 
          lapply(a, as.character)), ## but won't work with factors; convert to char
            useNA = "no")           ## we don't want NA values
           )[levels(a[[1]]), ]      ## We want our rows in a nicer order
    #     sickness1 sickness3 sickness4 sickness5
    # 3           2         1         1         1
    # 25          1         1         1         1
    # 50          2         2         1         1
    # 75          3         1         2         1
    # 97          1         1         1         1
    # 100         1         2         2         3
    

    或者,这里有一个“dplyr”+“tidyr”的方法:

    library(dplyr)
    library(tidyr)
    
    a %>% gather(var, val, sickness1:sickness5) %>%     ## make the data long
      mutate(val = factor(val, levels(unlist(a)))) %>%  ## refactor "val" column
      rev %>%                         ## reverse the order of val and var
      table %>%                       ## make your table
      as.data.frame.matrix            ## convert it to a data.frame
    
    #     sickness1 sickness3 sickness4 sickness5
    # 3           2         1         1         1
    # 25          1         1         1         1
    # 50          2         2         1         1
    # 75          3         1         2         1
    # 97          1         1         1         1
    # 100         1         2         2         3
    

    【讨论】:

    • 非常感谢!特别是对于解释!只有一个部分我不明白,那就是(.) 是什么意思?它只是意味着“使用前一行的输出”吗?这个参数是基础包的一部分还是另一个包的一部分?只有一个小错误:在gather() 参数中,列是sickness1:sickness4 而不是sickness5
    • @grrgrrbla,. 是在评估点之前引用数据集的简写。我已经编辑了答案以展示如何在没有. 的情况下工作。另外,gather 中的错误是你的——不是我的。请查看您的实际问题以了解我的意思。
    • 你是对的,对不起。我刚刚修复了操作。非常感谢,学到了更多有用的东西!
    【解决方案3】:

    你可以试试:

     un1 <- as.character(sort(unique(unlist(a, use.names=FALSE))))
     data.frame(percent=un1,do.call(cbind,
              lapply(a, function(x) table(factor(x, levels=un1)))))
    

    【讨论】:

    • 非常感谢!非常优雅的解决方案。一开始对我来说有点难以理解,但我和平地解开它,我明白了。现在了解了一些新功能,即使在阅读了一些关于它的内容后我仍然不明白 do.call 。不过,在接受您的回答之前,我会等待,因为我想听听其他解决方案:)。希望没问题
    • @grrgrrbia 是的,没关系。我使用的a 是在a[] &lt;- lapply(a, factor,..) 步骤之后。我认为这一步也可以避免。
    猜你喜欢
    • 2015-10-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-10
    • 1970-01-01
    相关资源
    最近更新 更多