从一组观察结果中创建队列式数据框
Creating cohort-style data frame from set of observations
我是 R 的新手,有一个简单的问题,因为我仍在学习 R 数据的样式 manipulation/management。
我有一段时间内对基本临床特征(血压、胆固醇等)的观察数据集。每个观察都有一个患者 ID 和日期,但作为单独的行项目输入。像这样:
Patient ID Date Blood Pressure
1 21/1/14 120
1 19/3/14 134
1 3/5/14 127
我想转换数据,以便对于给定的变量(例如血压),我有一个数据框,每个患者一行,所有血压值按时间顺序观察。像这样:
Patient ID BP1 BP2 BP3
1 120 134 127
我想这样做是因为我希望能够编写代码 select 例如,前三个观察到的血压的平均值。
如有任何建议或阅读建议,我们将不胜感激。
您可以通过多种方法重塑数据来实现所需的格式,包括使用 Base R 中的 reshape()
函数或 reshape2
包中的 dcast()
,但它可能使用聚合形式直接获得答案会更容易。这是使用 plyr
包中的 ddply()
的一种方法:
library(plyr)
df <- read.table(text="id date bp
1 21/1/14 120
1 19/3/14 134
1 3/5/14 127",header=TRUE)
df1 <- ddply(df, .(id), summarize, mean.bp = mean(bp[1:3]))
df1
# id mean.bp
# 1 1 127
当然,如果你真的只是想做你问的事情,你可以这样做:
library(reshape2)
df$bp.id <- ave(df$id,df$id,FUN=function(x) paste0("BP",seq(along=x)))
df2 <- dcast(df[df$bp.id %in% paste0("BP",1:3)], id~bp.id, value.var="bp")
df2
# id BP1 BP2 BP3
# 1 1 120 134 127
# example dataframe
id <- c(rep(1:4,25))
date <- c(rep("21/01/14",30),rep("21/01/14",30),rep("22/01/14",30),rep("23/01/14",10))
bp <- c(rnorm(100,100))
df <- data.frame(id,date,bp)
# reorder the dataframe
library(dplyr)
df2 <- group_by(df,id) # group by id
df2 <- arrange(df2, date) # order each group by date
df3 <- mutate(df2, # add a colum with ascending number per for each group
c = 1:length(date))
# use dcast
library(reshape2)
dcast(df3[,c(1,4,3)],id~c)
使用 data.table package (which has an improved implementation of the melt
and dcast
functions of reshape2) 您可以按如下方式执行此操作:
newdf <- dcast(setDT(df)[, idx := 1:.N, by = id], id ~ paste0("bp",idx), value.var = "bp")
或利用新的 rowid
函数:
newdf <- dcast(setDT(df), id ~ rowid(prefix="bp",id), value.var = "bp")
两个选项给出相同的结果:
> newdf
id bp1 bp2 bp3
1: 1 120 134 129
2: 2 110 124 119
但是正如@SamDickson 所说,当您想计算(例如)前两次血压测量值的平均值时,您还可以向现有数据框 df
添加一个新变量,其中:
# using base R
df$first2mn <- ave(df$bp, df$id, FUN = function(x) mean(x[1:2]))
# using data.table
setDT(df)[, first2mn := mean(bp[1:2]), id]
两者都给出:
> df
id date bp first2mn
1: 1 21/1/14 120 127
2: 1 19/3/14 134 127
3: 1 3/5/14 129 127
4: 2 21/1/14 110 117
5: 2 19/3/14 124 117
6: 2 3/5/14 119 117
或者只计算平均值:
# using base R
aggregate(bp ~ id, df, function(x) mean(x[1:2]))
# using data.table
setDT(df)[, .(bp = mean(bp[1:2])), id]
两者都给出:
id bp
1 1 127
2 2 117
已用数据:
df <- read.table(text="id date bp
1 21/1/14 120
1 19/3/14 134
1 3/5/14 129
2 21/1/14 110
2 19/3/14 124
2 3/5/14 119", header=TRUE)
其他答案提供了多种计算组间平均值的方法。 related post 提供了多种计算组级别最大值的方法。您需要将这些答案中的 max
替换为 mean
。
这是使用基本 R 函数重塑宽度的另一种方法 reshape
。
使用@jaap提供的data.frame,添加一个变量,用于按ID统计观察值:
df$times <- ave(df$bp, df$id, FUN=seq_along)
现在,执行整形,删除不需要的日期变量:
reshape(df, direction="wide", drop="date", timevar="times")
id bp.1 bp.2 bp.3
1 1 120 134 129
4 2 110 124 119
我是 R 的新手,有一个简单的问题,因为我仍在学习 R 数据的样式 manipulation/management。
我有一段时间内对基本临床特征(血压、胆固醇等)的观察数据集。每个观察都有一个患者 ID 和日期,但作为单独的行项目输入。像这样:
Patient ID Date Blood Pressure
1 21/1/14 120
1 19/3/14 134
1 3/5/14 127
我想转换数据,以便对于给定的变量(例如血压),我有一个数据框,每个患者一行,所有血压值按时间顺序观察。像这样:
Patient ID BP1 BP2 BP3
1 120 134 127
我想这样做是因为我希望能够编写代码 select 例如,前三个观察到的血压的平均值。
如有任何建议或阅读建议,我们将不胜感激。
您可以通过多种方法重塑数据来实现所需的格式,包括使用 Base R 中的 reshape()
函数或 reshape2
包中的 dcast()
,但它可能使用聚合形式直接获得答案会更容易。这是使用 plyr
包中的 ddply()
的一种方法:
library(plyr)
df <- read.table(text="id date bp
1 21/1/14 120
1 19/3/14 134
1 3/5/14 127",header=TRUE)
df1 <- ddply(df, .(id), summarize, mean.bp = mean(bp[1:3]))
df1
# id mean.bp
# 1 1 127
当然,如果你真的只是想做你问的事情,你可以这样做:
library(reshape2)
df$bp.id <- ave(df$id,df$id,FUN=function(x) paste0("BP",seq(along=x)))
df2 <- dcast(df[df$bp.id %in% paste0("BP",1:3)], id~bp.id, value.var="bp")
df2
# id BP1 BP2 BP3
# 1 1 120 134 127
# example dataframe
id <- c(rep(1:4,25))
date <- c(rep("21/01/14",30),rep("21/01/14",30),rep("22/01/14",30),rep("23/01/14",10))
bp <- c(rnorm(100,100))
df <- data.frame(id,date,bp)
# reorder the dataframe
library(dplyr)
df2 <- group_by(df,id) # group by id
df2 <- arrange(df2, date) # order each group by date
df3 <- mutate(df2, # add a colum with ascending number per for each group
c = 1:length(date))
# use dcast
library(reshape2)
dcast(df3[,c(1,4,3)],id~c)
使用 data.table package (which has an improved implementation of the melt
and dcast
functions of reshape2) 您可以按如下方式执行此操作:
newdf <- dcast(setDT(df)[, idx := 1:.N, by = id], id ~ paste0("bp",idx), value.var = "bp")
或利用新的 rowid
函数:
newdf <- dcast(setDT(df), id ~ rowid(prefix="bp",id), value.var = "bp")
两个选项给出相同的结果:
> newdf
id bp1 bp2 bp3
1: 1 120 134 129
2: 2 110 124 119
但是正如@SamDickson 所说,当您想计算(例如)前两次血压测量值的平均值时,您还可以向现有数据框 df
添加一个新变量,其中:
# using base R
df$first2mn <- ave(df$bp, df$id, FUN = function(x) mean(x[1:2]))
# using data.table
setDT(df)[, first2mn := mean(bp[1:2]), id]
两者都给出:
> df
id date bp first2mn
1: 1 21/1/14 120 127
2: 1 19/3/14 134 127
3: 1 3/5/14 129 127
4: 2 21/1/14 110 117
5: 2 19/3/14 124 117
6: 2 3/5/14 119 117
或者只计算平均值:
# using base R
aggregate(bp ~ id, df, function(x) mean(x[1:2]))
# using data.table
setDT(df)[, .(bp = mean(bp[1:2])), id]
两者都给出:
id bp
1 1 127
2 2 117
已用数据:
df <- read.table(text="id date bp
1 21/1/14 120
1 19/3/14 134
1 3/5/14 129
2 21/1/14 110
2 19/3/14 124
2 3/5/14 119", header=TRUE)
其他答案提供了多种计算组间平均值的方法。 related post 提供了多种计算组级别最大值的方法。您需要将这些答案中的 max
替换为 mean
。
这是使用基本 R 函数重塑宽度的另一种方法 reshape
。
使用@jaap提供的data.frame,添加一个变量,用于按ID统计观察值:
df$times <- ave(df$bp, df$id, FUN=seq_along)
现在,执行整形,删除不需要的日期变量:
reshape(df, direction="wide", drop="date", timevar="times")
id bp.1 bp.2 bp.3
1 1 120 134 129
4 2 110 124 119