【问题标题】:Create stacked area graph from time data根据时间数据创建堆积面积图
【发布时间】:2014-03-20 20:39:57
【问题描述】:

我是一名社会科学研究人员,致力于想象人们如何随着时间的推移在社区中扮演不同的角色。

我已将人们每月的行为归类为角色类别,现在我想可视化每个(相对)时间段内每个角色的人数和比例。

现在,数据保存在 CSV 格式中,如下所示:

ID  T1  T2  T3 ...
1   2   2   3
2   1   0   2
3   1   2   1
...

其中 X(ij) 是我在第 j 个月所处的集群 ID。

我想要的是这样的(我在 LibreOffice 中创建的)。

我相信我需要使用 ggplot2,但我一直在努力弄清楚如何以 ggplot 喜欢的格式获取数据。

我想我的第一个任务是总结每个时间段的每个集群?有没有简单的方法可以做到这一点?

我可以用下面的代码做到这一点,但是它很糟糕而且很乱,一定有更好的方法吗?

clus1 <- apply(clusters, 2, function(x) {sum(x=='1', na.rm=TRUE)})
clus2 <- apply(clusters, 2, function(x) {sum(x=='2', na.rm=TRUE)})
clus3 <- apply(clusters, 2, function(x) {sum(x=='3', na.rm=TRUE)})
clus0 <- apply(clusters, 2, function(x) {sum(x=='0', na.rm=TRUE)})
clusters2 <- data.frame(clus0, clus1, clus2, clus3)
c2 <- t(clusters2)
c3 <- as.data.frame(c2)
c3$id = c('Low Activity Cluster', 'Cluster 1', 'Cluster 2', 'Cluster 3')
c3 <- c3[order(c3$'id'),]
print(ggplot(melt(c3, id.vars="id")) +
  geom_area(aes(x=variable, y=value, fill=id, group=id), position="fill"))

这会导致示例数据如下所示:

id                      T1  T2  T3
Low Activity Cluster     0   1   0
Cluster 1                2   0   1
Cluster 2                1   2   1
Cluster 3                0   0   1

这是正确的策略吗?

【问题讨论】:

    标签: r ggplot2 reshape


    【解决方案1】:

    编辑,试图解决 cmets:

    `rownames<-`(
      as.data.frame(lapply(df[-1], function(x) as.numeric(table(x)))), 
      paste("Clust ", 0:3)
    )
    

    生产:

             T1 T2 T3 T4 T5 T6 T7 T8 T9 T10
    Clust  0  4  3  5  8 11  6  2  4  5   7
    Clust  1  5  9  8  6  3  7  7  8  7   4
    Clust  2  5  6  2  3  3  3  2  3  4   4
    Clust  3  6  2  5  3  3  4  9  5  4   5
    

    这使用table 计算每个时间段内每种集群类型的出现次数 (0:3)。关键代码是lapply(...)。它周围的东西看起来很漂亮。

    有数据:

    set.seed(1)
    labels <- paste("Clust ", 0:3)
    df <- as.data.frame(c(list(ID=1:20), setNames(replicate(10, factor(sample(0:3, 20, rep=T)), simplify=F), paste0("T", 1:10))))
    

    这是一个ggplot 解决方案。首先,您需要使用 reshape2 包中的 melt 将数据转换为长格式,然后您可以将其聚合(可选择重新转换),然后绘制它:

    library(reshape2)
    library(ggplot2)
    df.mlt <- melt(df, id.vars="ID")
    df.agg <- aggregate(. ~ ID + variable, df.mlt, sum)
    dcast(df.agg, ID ~ variable)  # just for show, we don't use the result anyplace
    
    #   ID T1 T2 T3 T4 T5 T6 T7 T8 T9 T10
    # 1  0 25 18 29 23 16 15 14 22 29  19
    # 2  1  7  7 14 18 19 11 21 17 15  22
    # 3  2 16 15 16 20 23 20 16 13 15  12
    # 4  3 14 13 20 17 25 14 13  7 21  24
    
    ggplot(df.agg) +
      geom_area(aes(x=variable, y=value, fill=ID, group=ID), position="fill") 
    

    需要一点时间来适应ggplot,但是一旦你习惯了它就会很直观。您应该先查看melt(df, id.vars="ID") 的结果,以了解我所说的“长格式”是什么意思。然后,在这种情况下,我们使用geom_area,并在aes 中将x 值指定为“美学”(随数据变化的值)(variable 是由melt 生成的名称,在此如果它包含time 值),y 值(value 也是由melt 创建的),还指定我们区域的填充颜色应该来自ID。请注意,因为我们在这里使用的时间是分类的(T1、T2 等,而不是实际日期),所以除了 fill 之外,我们必须使用 group 以便 ggplot 知道您想要不同的点连接时间。

    请注意,您不需要在绘图之前执行聚合步骤。 ggplot 可以在内部处理。以下命令是等效的(注意我们如何使用df.mlt):

    ggplot(df.mlt) +
      stat_summary(aes(x=variable, y=value, fill=ID, group=ID), fun.y=sum, position="fill", geom="area") 
    

    这是我使用的数据:

    df <- as.data.frame(c(list(ID=rep(factor(0:3), 3)), setNames(replicate(10, sample(1:10, 12, rep=T), simplify=F), paste0("T", 1:10))))
    

    【讨论】:

    • 这真的很有帮助,但我认为这是问题的后半部分。我可能对上半场不够清楚。我不想绘制每个用户的角色如何随时间变化 - 相反,我想绘制所有角色随时间的比率。我将调整原始问题以澄清。
    • 我不确定我做错了什么,但这不起作用。我的 df.agg 有 3 列 - id、variable 和 value,其中 value 只是当时该用户的集群。我正在向我的问题添加一些 cmets,其中包含一些似乎有效的代码,尽管它是复杂的代码。
    • @Jeremy,这很正常。查看下一步(dcast)。这会将三列格式(长格式)转换为您想要看到的内容(宽格式)。大多数对组(包括ggplot)进行操作的 R 分析工具都使用长格式数据(在本例中为三列版本)。
    • 我觉得问题可能是我对原始数据的解释不够好。第一列 (ID) 表示用户 ID,而不是集群 ID。因此,有数千行具有不同的 ID。我的目标是每次聚合跨 ID 的集群值(即表中的值)。作为旁注,非常感谢,非常感谢您的帮助!!!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-11-17
    • 2018-06-17
    • 1970-01-01
    • 2015-12-09
    • 2021-02-14
    • 2013-05-28
    • 1970-01-01
    相关资源
    最近更新 更多