在 R 中匹配和汇总数据框
Match and summarize dataframe in R
我有一个包含时间序列数据列以及开始年份和结束年份的数据框。
df = data.frame(y2000=c(12,636),y2001=c(234, 76),y2002=c(3434, 46),y2003=c(36,35),y2004=c(6, 64), y2005=c(56,65), y2006=c(43,65), y2007=c( 6, 56),y2008=c( 64, 66),y2009=c(63, 5656),y2010 = c(65,54),startyear= c(2006, 2001), endyear= c(2009, 2005))
对于每一行,我想计算开始和结束年份以及开始和结束期间之前和之后的平均值。所需的输出如下所示:
y2000 y2001 y2002 y2003 y2004 y2005 y2006 y2007 y2008 y2009 y2010 startyear endyear before_mean within_mean after_mean
12 234 3434 36 6 56 43 6 64 63 65 2006 2009 629.6666667 44 65
636 76 46 35 64 65 65 56 66 5656 54 2001 2005 636 57.2 1179.4
我尝试过不同的匹配和索引技术,但无法完全理解这个。
1. dplyr/tidyr
将'wide'格式转换为'long'格式可能会更好。我们可以使用 dplyr/tidyr
来获得 mean
。创建一个 'ind' 列,使用 gather
将数据重塑为 'long',将 'variable' 列拆分为两列('var1'、'var2') extract
,按 'ind' 分组,根据创建的不同逻辑索引(即 var2 < startyear
、var2 >= startyear & var2 <= endyear
, 和 var2 >endyear
)
library(dplyr)
library(tidyr)
dS <- df %>%
mutate(ind=row_number()) %>%
gather(variable, value, starts_with('y')) %>%
extract(variable, c('var1', 'var2'), '([^0-9]+)([0-9]+)',
convert=TRUE) %>%
group_by(ind) %>%
summarise(before_mean= mean(value[var2 < startyear]),
within_mean = mean(value[var2 >= startyear &
var2 <= endyear]),
after_mean=mean(value[var2 >endyear])) %>%
as.data.frame()
nm1 <- paste(c('before', 'within', 'after'), 'mean', sep="_")
dS
# ind before_mean within_mean after_mean
#1 1 629.6667 44.0 65.0
#2 2 636.0000 57.2 1179.4
我们可以根据上面的输出
在'df'中创建额外的列
df[nm1] <- dS
2。基础 R
我们可以使用 base R
方法并且不改变数据集的格式。从原始数据集 ('df') 中,为数字列名称创建索引 ('indx'),删除非数字部分并转换为数字 ('v1')。
indx <- grep('\d+', names(df))
v1 <- as.numeric(sub('[^0-9]+', '', names(df)[indx]))
循环 'df' (lapply
),match
'startyear' 与 'v1' 的行,使用该索引 ('i1')获取列 unlist
,并计算 mean
。同样可以通过将 'endyear' 与 'v1' 匹配以获得索引 ('i2') 来完成。根据'i1'和'i2',计算出'within_mean'和'after_mean'。 rbind
列表元素并将输出分配给 'df'.
中的新列 ('nm1')
df[nm1] <- do.call(rbind,lapply(1:nrow(df), function(i) {
i1 <- match(df$startyear[i], v1)
before_mean<- mean(unlist(df[i,1:(i1-1),drop=FALSE]))
i2 <- match(df$endyear[i], v1)
within_mean <- mean(unlist(df[i,i2:i1]))
after_mean <- mean(unlist(df[i,match(v1[(i2+1):length(v1)],v1)]))
data.frame(before_mean,within_mean, after_mean) }))
df[nm1]
# before_mean within_mean after_mean
#1 629.6667 44.0 65.0
#2 636.0000 57.2 1179.4
这是一个解决方案:
#The original data:
df = data.frame(y2000=c(12,636),y2001=c(234, 76),y2002=c(3434, 46),y2003=c(36,35),y2004=c(6, 64), y2005=c(56,65), y2006=c(43,65), y2007=c( 6, 56),y2008=c( 64, 66),y2009=c(63, 5656),y2010 = c(65,54),startyear= c(2006, 2001), endyear= c(2009, 2005))
df$s = df$startyear - 1999
df$e = df$endyear - 1999
df$before_mean <- apply(df, 1, function(x)sum(x[1:(x[14]-1)] ))
df$within_mean <- apply(df, 1, function(x)sum(x[x[14]:x[15]] ))
df$after_mean <- apply(df, 1, function(x)sum(x[(x[15]+1):11] ))
df$s <- NULL
df$e <- NULL
此解决方案与示例中的确切年份相关联,但使其更通用并不难。
不同于 akrun 的另一种方法,也使用 Base R。我们将创建一个中间变量,其顺序与列名相同,但具有数字格式。这将用于引用实际数据框的列:
col.years <- suppressWarnings(as.numeric(sub("^y", "", colnames(df))))[1:11]
# Initialise everything to NA (better when preparing to loop over df)
df$before_mean <- NA
df$within_mean <- NA
df$after_mean <- NA
for(i in seq_len(nrow(df))) {
df$before_mean[i] <- mean(as.numeric(df[i, which(col.years < df$startyear[i])]))
df$within_mean[i] <- mean(as.numeric(df[i, which((col.years >= df$startyear[i]) & (col.years <= df$endyear[i]))]))
df$after_mean[i] <- mean(as.numeric(df[i, which(col.years > df$endyear[i])]))
}
结果
df[,14:16]
# before_mean within_mean after_mean
# 1 629.6667 44.0 65.0
# 2 636.0000 57.2 1179.4
我有一个包含时间序列数据列以及开始年份和结束年份的数据框。
df = data.frame(y2000=c(12,636),y2001=c(234, 76),y2002=c(3434, 46),y2003=c(36,35),y2004=c(6, 64), y2005=c(56,65), y2006=c(43,65), y2007=c( 6, 56),y2008=c( 64, 66),y2009=c(63, 5656),y2010 = c(65,54),startyear= c(2006, 2001), endyear= c(2009, 2005))
对于每一行,我想计算开始和结束年份以及开始和结束期间之前和之后的平均值。所需的输出如下所示:
y2000 y2001 y2002 y2003 y2004 y2005 y2006 y2007 y2008 y2009 y2010 startyear endyear before_mean within_mean after_mean
12 234 3434 36 6 56 43 6 64 63 65 2006 2009 629.6666667 44 65
636 76 46 35 64 65 65 56 66 5656 54 2001 2005 636 57.2 1179.4
我尝试过不同的匹配和索引技术,但无法完全理解这个。
1. dplyr/tidyr
将'wide'格式转换为'long'格式可能会更好。我们可以使用 dplyr/tidyr
来获得 mean
。创建一个 'ind' 列,使用 gather
将数据重塑为 'long',将 'variable' 列拆分为两列('var1'、'var2') extract
,按 'ind' 分组,根据创建的不同逻辑索引(即 var2 < startyear
、var2 >= startyear & var2 <= endyear
, 和 var2 >endyear
)
library(dplyr)
library(tidyr)
dS <- df %>%
mutate(ind=row_number()) %>%
gather(variable, value, starts_with('y')) %>%
extract(variable, c('var1', 'var2'), '([^0-9]+)([0-9]+)',
convert=TRUE) %>%
group_by(ind) %>%
summarise(before_mean= mean(value[var2 < startyear]),
within_mean = mean(value[var2 >= startyear &
var2 <= endyear]),
after_mean=mean(value[var2 >endyear])) %>%
as.data.frame()
nm1 <- paste(c('before', 'within', 'after'), 'mean', sep="_")
dS
# ind before_mean within_mean after_mean
#1 1 629.6667 44.0 65.0
#2 2 636.0000 57.2 1179.4
我们可以根据上面的输出
在'df'中创建额外的列df[nm1] <- dS
2。基础 R
我们可以使用 base R
方法并且不改变数据集的格式。从原始数据集 ('df') 中,为数字列名称创建索引 ('indx'),删除非数字部分并转换为数字 ('v1')。
indx <- grep('\d+', names(df))
v1 <- as.numeric(sub('[^0-9]+', '', names(df)[indx]))
循环 'df' (lapply
),match
'startyear' 与 'v1' 的行,使用该索引 ('i1')获取列 unlist
,并计算 mean
。同样可以通过将 'endyear' 与 'v1' 匹配以获得索引 ('i2') 来完成。根据'i1'和'i2',计算出'within_mean'和'after_mean'。 rbind
列表元素并将输出分配给 'df'.
df[nm1] <- do.call(rbind,lapply(1:nrow(df), function(i) {
i1 <- match(df$startyear[i], v1)
before_mean<- mean(unlist(df[i,1:(i1-1),drop=FALSE]))
i2 <- match(df$endyear[i], v1)
within_mean <- mean(unlist(df[i,i2:i1]))
after_mean <- mean(unlist(df[i,match(v1[(i2+1):length(v1)],v1)]))
data.frame(before_mean,within_mean, after_mean) }))
df[nm1]
# before_mean within_mean after_mean
#1 629.6667 44.0 65.0
#2 636.0000 57.2 1179.4
这是一个解决方案:
#The original data:
df = data.frame(y2000=c(12,636),y2001=c(234, 76),y2002=c(3434, 46),y2003=c(36,35),y2004=c(6, 64), y2005=c(56,65), y2006=c(43,65), y2007=c( 6, 56),y2008=c( 64, 66),y2009=c(63, 5656),y2010 = c(65,54),startyear= c(2006, 2001), endyear= c(2009, 2005))
df$s = df$startyear - 1999
df$e = df$endyear - 1999
df$before_mean <- apply(df, 1, function(x)sum(x[1:(x[14]-1)] ))
df$within_mean <- apply(df, 1, function(x)sum(x[x[14]:x[15]] ))
df$after_mean <- apply(df, 1, function(x)sum(x[(x[15]+1):11] ))
df$s <- NULL
df$e <- NULL
此解决方案与示例中的确切年份相关联,但使其更通用并不难。
不同于 akrun 的另一种方法,也使用 Base R。我们将创建一个中间变量,其顺序与列名相同,但具有数字格式。这将用于引用实际数据框的列:
col.years <- suppressWarnings(as.numeric(sub("^y", "", colnames(df))))[1:11]
# Initialise everything to NA (better when preparing to loop over df)
df$before_mean <- NA
df$within_mean <- NA
df$after_mean <- NA
for(i in seq_len(nrow(df))) {
df$before_mean[i] <- mean(as.numeric(df[i, which(col.years < df$startyear[i])]))
df$within_mean[i] <- mean(as.numeric(df[i, which((col.years >= df$startyear[i]) & (col.years <= df$endyear[i]))]))
df$after_mean[i] <- mean(as.numeric(df[i, which(col.years > df$endyear[i])]))
}
结果
df[,14:16]
# before_mean within_mean after_mean
# 1 629.6667 44.0 65.0
# 2 636.0000 57.2 1179.4