从一组观测数据中创建队列式数据框架

4

我是R语言的新手,有一个简单问题,请教一下。因为我还在学习R数据操作和管理的风格。

我的数据集记录了一段时间内基本临床特征(血压、胆固醇等)的观察结果,每个观测值都有患者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

我希望这样做是因为我想编写代码来选择前三个观测到的血压平均值,例如。

如有建议或阅读推荐,将不胜感激。

4个回答

3

您可以通过许多方法重塑数据,包括使用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

ave/dcast 的使用很好。加一。 - akrun
我正在尝试使用您提供的第二个选项(使用reshape2)。使用您上面编写的确切代码,它返回以下错误:Error in [.data.frame(df, df$bp.id %in% paste0("BP", 1:3)) : undefined columns selected。有什么想法吗?每个id都有超过3个bp观察值(最大为14),当我将1:3更改为1:14时,仍然会出现相同的错误。 - James
由于某种原因,我错过了逗号,但它仍然对我有效。首先尝试这个:df2 <- dcast(df, id~bp.id, value.var="bp")。如果这不起作用,请尝试这个df2 <- dcast(df[df$bp.id %in% paste0("BP",1:3),], id~bp.id, value.var="bp")或这个df2 <- dcast(df[grep("BP",df$bp.id),], id~bp.id, value.var="bp") - Sam Dickson

3
 # 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)

3

使用包(该包具有 meltdcast 函数的改进实现),您可以按照以下方式执行此操作:

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)

0
其他回答已经提供了一些计算组间平均值的方法。相关文章提供了一些计算组级最大值的方法。在这些答案中,您需要将max替换为mean
这里有一种使用基本R函数reshape重新塑形宽数据的附加方法。
使用@jaap提供的data.frame,添加一个变量来按ID计数观测值:
df$times <- ave(df$bp, df$id, FUN=seq_along)

现在,执行reshape操作,删除不需要的日期变量:

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接