将间隔截尾的随访时间绘制为折线图

机器算法验证 r 数据可视化 生存
2022-03-19 12:43:28

我正在做一个生存分析项目,在这个项目中可视化每个人的跟进时间和事件时间会很有用。数据由一个 ID、两个可能事件中的哪一个(A 或 B)、他们发生事件的时间以及它们是否被间隔审查组成。非审查个体有两个相同的事件时间,t1 和 t2,而审查个体有 t1 =/= t2,给出审查时间的下限和上限。

这看起来像这样(全部组成):

ID, eventA, eventB, t1, t2, censored
1, 0, 1, 7, 7, 0
2, 1, 0, 5, 5, 0 
3, 1, 0, 10, 10, 0
4, 0, 1, 4.5, 4.5, 0
5, 1, 0, 2, 8, 1

其中 ID 5 被审查。

我想制作这样的情节:

在此处输入图像描述

本质上,制作 X 轴 ID,Y 轴时间。画一条从 0 到 t1 的线段。然后,如果它们被审查,则从 t1 到 t2 绘制另一条线段。据推测,如果它们未经审查,它们只会重叠,这很好。然后为每种类型的事件在 t2 处放置一个标记,如果它们是 eventA,则说 X,如果它们是 eventB,则说 O。

我认为在 R 中有一种方法可以做到这一点,但我还没有真正将注意力集中在 R 中的图形上,而且我发现的大多数生存分析中的图形示例都是 KM 曲线。有人有想法吗?

2个回答

必须有很多方法可以使用间隔删失数据制作后续时间图,尽管快速的谷歌搜索只审查概览中找到了这张图片,这在我看来有点忙。

只是为了给出另一个观点,这是一种使用 ggplot2 包的方法。

require(ggplot2)

# Your example data
dat <- structure(list(ID = 1:5, eventA = c(0L, 1L, 1L, 0L, 1L), 
    eventB = c(1L, 0L, 0L, 1L, 0L), t1 = c(7, 5, 10, 4.5, 2), t2 = c(7, 5, 10, 4.5, 
    8), censored = c(0, 0, 0, 0, 1)), .Names = c("ID", "eventA", 
    "eventB", "t1", "t2", "censored"), class = "data.frame", row.names = c(NA, -5L))

# Create event variable
dat$event <- with(dat, ifelse(eventA, "A", "B"))

# Create id.ordered, which is a factor that is ordered by t2
# This will allow the plot to be ordered by increasing t2, if desired
dat$id.ordered <- factor(x = dat$ID, levels = order(dat$t2, decreasing = T))

# Use ggplot to plot data from dat object
ggplot(dat, aes(x = id.ordered)) + 
    # Plot solid line representing non-interval censored time from 0 to t1
    geom_linerange(aes(ymin = 0, ymax = t1)) + 
    # Plot line (dotted for censored time) representing time from t1 to t2
    geom_linerange(aes(ymin = t1, ymax = t2, linetype = as.factor(censored))) +  
    # Plot points representing event
    # The ifelse() function moves censored marker to middle of interval
    geom_point(aes(y = ifelse(censored, t1 + (t2 - t1) / 2, t2), shape = event), 
        size = 4) +
    # Flip coordinates
    coord_flip() + 
    # Add custom name to linetype scale, 
    # otherwise it will default to "as.factor(censored))"
    scale_linetype_manual(name = "Censoring", values = c(1, 2), 
        labels = c("Not censored", "Interval censored")) +
    # Add custom shape scale.  Change the values to get different shapes.
    scale_shape_manual(name = "Event", values = c(19, 15)) +
    # Add main title and axis labels
    opts(title = "Patient follow-up") + xlab("Patient ID") +  ylab("Days") + 
    # I think the bw theme looks better for this graph, 
    # but leave it out if you prefer the default theme
    theme_bw()

结果:

间隔删失数据的患者随访

在根据数据制作具有线型、颜色、大小等的图形时,我发现 ggplot2 比基本图形甚至格状图更直观,尽管格状图在绘制更大的数据时要快得多。

我不确定是否最好将事件标记放置在审查间隔的中间或末尾。我这里选择了中间,强调事件不一定发生在接近尾声的时候。

附录

一旦您决定了一个标准绘图,并且如果您发现自己经常制作这些绘图,则可以方便地将其包装在一个函数中并使用 R 的 S3 对象系统通过调用plot()泛型来调度绘图方法。以下内容与原始问题没有直接关系,但为了其他有兴趣向plot()泛型添加方法的读者,我将在此处包含它。首先,将 ggplot 调用封装到 plot 方法函数中:

plot.interval.censored <- function(x, title = "Patient follow-up", 
        xlab = "Patient ID", ylab = "Days",
        linetype.values = c(1, 2), shape.values = c(19, 15))
{
    x$event <- with(dat, ifelse(eventA, "A", "B"))
		x$id.ordered <- factor(x = dat$ID, levels = order(dat$t2, decreasing = T))

    out <- ggplot(x, aes(x = id.ordered)) + 
            geom_linerange(aes(ymin = 0, ymax = t1)) + 
            geom_linerange(aes(ymin = t1, ymax = t2, linetype = as.factor(censored))) +  
            geom_point(aes(y = ifelse(censored, t1 + (t2 - t1) / 2, t2), shape = event), 
                    size = 4) +
            coord_flip() + 
            scale_linetype_manual(name = "Censoring", values = linetype.values, 
                    labels = c("Not censored", "Interval censored")) +
            scale_shape_manual(name = "Event", values = shape.values) +
            opts(title = title) + xlab(xlab) +  ylab(ylab) + 
            theme_bw()

    return(out)
}

然后,添加internal.censored到数据对象的类中:

class(dat) <- c("interval.censored", class(dat))

现在,只需调用以下命令即可生成该图:

plot(dat)

您可以将其plot.interval.censored()放入一个包中,也可以将其添加到您的 .Rprofile 中,在这种情况下,当您在计算机上启动 R 时,它始终可供您使用。发布包可能是首选,因为当您不在自己的计算机上时,它更容易与他人共享或安装。但是,编辑 .Rprofile 可能更简单。Hadley 对 S3 对象系统有一个很好的概述

嗯,那是……相当容易。Visualize This中不相关的图表的启发:

plot(data$t2, type="h", col="grey", lwd=2, xlab="Subject", ylab="Days Since Start")
    lines(data$t1, type="h", col="lightskyblue", lwd=2)
points(data$atime, pch=19, cex=0.75, col="Black")

决定为整个队列添加 A 和 B 的标记有点拥挤,所以这只是用 A 的标记显示,但它显然是可推广的。在错误的方向上也是如此,但这并不是什么大不了的事,而且在修修补补的领域。