用R中的条件计算多列的平均值
我想计算几个变量的平均值,但有条件的话,如果其中两列有NA,平均值就是NA,如果小于2,就求平均值用R中的条件计算多列的平均值,r,mean,R,Mean,我想计算几个变量的平均值,但有条件的话,如果其中两列有NA,平均值就是NA,如果小于2,就求平均值 df <- data.frame(ID = c(1:10),X1 = c(rep(1,5),rep(2,5)),X2 = c(1:10),X3 = c(1,NA,2,NA,NA,1,NA,2,NA,NA),X4 = c(rep(NA,10)),X5=c(rep(1,5),rep(NA,5)), Y1 = c(rep(1,5),rep(2,5)),Y2 = c(1
df <- data.frame(ID = c(1:10),X1 = c(rep(1,5),rep(2,5)),X2 = c(1:10),X3 = c(1,NA,2,NA,NA,1,NA,2,NA,NA),X4 = c(rep(NA,10)),X5=c(rep(1,5),rep(NA,5)),
Y1 = c(rep(1,5),rep(2,5)),Y2 = c(1:10),Y3 = c(1,NA,2,NA,NA,1,NA,2,NA,NA),Y4 = c(rep(NA,10)),Y5=c(rep(1,5),rep(NA,5)))
MeanX = round(apply(df[,c(2:6)],1, mean,na.rm = TRUE),2)
MeanY = round(apply(df[,c(7:11)],1,mean,na.rm = TRUE),2)
因为我有一个大的数据集,对于每个组,有时我必须设置20个中的6个,有时10个中的1个,所以我可以计算平均值,如何设置这种情况下的条件。这里是一个非常快速(必须运行)和肮脏的解决方案,包含数据。表
。但我相信它可以被清洗,并建立在它的基础上,使之整洁,工作良好
# Load data.table
require(data.table)
setDT(df)
# Format all columns as as numeric,
# otherwise mean is not meaningful (see what I did there?)
x.cols <- paste("X", 1:5, sep = "")
y.cols <- paste("Y", 1:5, sep = "")
setDT(df)[, (x.cols) := lapply(.SD, as.integer), .SDcols = x.cols]
setDT(df)[, (y.cols) := lapply(.SD, as.integer), .SDcols = y.cols]
# meanX first mean, and then NA
df[, meanX := mean(c(X1, X2, X3, X4, X5), na.rm = TRUE), by =ID]
df[df[, sum(is.na(c(X1, X2, X3, X4, X5))) > 2, by = ID]$V1, meanX := NA]
# meanY first mean, and then NA
df[, meanY := mean(c(Y1, Y2, Y3, Y4, Y5), na.rm = TRUE), by =ID]
df[df[, sum(is.na(c(Y1, Y2, Y3, Y4, Y5))) > 2, by = ID]$V1, meanY := NA]
# Result
df
ID X1 X2 X3 X4 X5 Y1 Y2 Y3 Y4 Y5 meanX meanY
1: 1 1 1 1 NA 1 1 1 1 NA 1 1.000000 1.000000
2: 2 1 2 NA NA 1 1 2 NA NA 1 1.333333 1.333333
3: 3 1 3 2 NA 1 1 3 2 NA 1 1.750000 1.750000
4: 4 1 4 NA NA 1 1 4 NA NA 1 2.000000 2.000000
5: 5 1 5 NA NA 1 1 5 NA NA 1 2.333333 2.333333
6: 6 2 6 1 NA NA 2 6 1 NA NA 3.000000 3.000000
7: 7 2 7 NA NA NA 2 7 NA NA NA NA NA
8: 8 2 8 2 NA NA 2 8 2 NA NA 4.000000 4.000000
9: 9 2 9 NA NA NA 2 9 NA NA NA NA NA
10: 10 2 10 NA NA NA 2 10 NA NA NA NA NA
#加载数据表
要求(数据表)
setDT(df)
#将所有列格式化为数字,
#否则意味着没有意义(看我在那里做了什么?)
x、 cols 2,by=ID]$V1,meanY:=NA]
#结果
df
ID X1 X2 X3 X4 X5 Y1 Y2 Y3 Y4 Y5平均值x平均值
1:111NA1110000001.000000
2:2112NA1112NA1113331.333333
3:31132NA13132NA111750000 1.750000
4:414Na11Na14Na120000002.000000
5:515Na115Na123332.333333
6:6261NA261NA33000000
7:727NaNaNa27NaNaNaNaNaNa
8:8282NA282NA440000000
9:929NaNa2Na9NaNaNaNaNaNa
10:1020NaNa210NaNaNaNaNaNaNa
这是一个非常快速(必须运行)且脏的解决方案,包含数据。表
。但我相信它可以被清洗,并建立在它的基础上,使之整洁,工作良好
# Load data.table
require(data.table)
setDT(df)
# Format all columns as as numeric,
# otherwise mean is not meaningful (see what I did there?)
x.cols <- paste("X", 1:5, sep = "")
y.cols <- paste("Y", 1:5, sep = "")
setDT(df)[, (x.cols) := lapply(.SD, as.integer), .SDcols = x.cols]
setDT(df)[, (y.cols) := lapply(.SD, as.integer), .SDcols = y.cols]
# meanX first mean, and then NA
df[, meanX := mean(c(X1, X2, X3, X4, X5), na.rm = TRUE), by =ID]
df[df[, sum(is.na(c(X1, X2, X3, X4, X5))) > 2, by = ID]$V1, meanX := NA]
# meanY first mean, and then NA
df[, meanY := mean(c(Y1, Y2, Y3, Y4, Y5), na.rm = TRUE), by =ID]
df[df[, sum(is.na(c(Y1, Y2, Y3, Y4, Y5))) > 2, by = ID]$V1, meanY := NA]
# Result
df
ID X1 X2 X3 X4 X5 Y1 Y2 Y3 Y4 Y5 meanX meanY
1: 1 1 1 1 NA 1 1 1 1 NA 1 1.000000 1.000000
2: 2 1 2 NA NA 1 1 2 NA NA 1 1.333333 1.333333
3: 3 1 3 2 NA 1 1 3 2 NA 1 1.750000 1.750000
4: 4 1 4 NA NA 1 1 4 NA NA 1 2.000000 2.000000
5: 5 1 5 NA NA 1 1 5 NA NA 1 2.333333 2.333333
6: 6 2 6 1 NA NA 2 6 1 NA NA 3.000000 3.000000
7: 7 2 7 NA NA NA 2 7 NA NA NA NA NA
8: 8 2 8 2 NA NA 2 8 2 NA NA 4.000000 4.000000
9: 9 2 9 NA NA NA 2 9 NA NA NA NA NA
10: 10 2 10 NA NA NA 2 10 NA NA NA NA NA
#加载数据表
要求(数据表)
setDT(df)
#将所有列格式化为数字,
#否则意味着没有意义(看我在那里做了什么?)
x、 cols 2,by=ID]$V1,meanY:=NA]
#结果
df
ID X1 X2 X3 X4 X5 Y1 Y2 Y3 Y4 Y5平均值x平均值
1:111NA1110000001.000000
2:2112NA1112NA1113331.333333
3:31132NA13132NA111750000 1.750000
4:414Na11Na14Na120000002.000000
5:515Na115Na123332.333333
6:6261NA261NA33000000
7:727NaNaNa27NaNaNaNaNaNa
8:8282NA282NA440000000
9:929NaNa2Na9NaNaNaNaNaNa
10:1020NaNa210NaNaNaNaNaNaNa
这是一个基本的R解决方案
我认为如果您首先使用长格式,这在概念上更容易,例如:
long <- reshape(df, idvar='ID', varying=colnames(df)[-1], timevar='t', sep='', direction='long')
然后,您可以根据您的描述相当自然地编写聚合函数。这一个匹配@snoram:
f <- function(x) if( sum(is.na(x)) > 2 ) NA else mean(x, na.rm=TRUE)
其中:
ID meanx meany
1 1 1.000000000 1.000000000
2 2 1.333333333 1.333333333
3 3 1.750000000 1.750000000
4 4 2.000000000 2.000000000
5 5 2.333333333 2.333333333
6 6 3.000000000 3.000000000
7 7 NA NA
8 8 4.000000000 4.000000000
9 9 NA NA
10 10 NA NA
然后,如果愿意,您可以cbind
将其返回到原始数据帧
这种方法的优点是,如果您也有X6、X7等,它应该可以轻松地处理它们
编辑:
重新阅读您的问题,您最好分别跟踪NAs的平均值和数量,然后进行后处理。下面是一个快速而肮脏的例子:
> f <- function(x) c(sum(is.na(x)), mean(x, na.rm=TRUE))
> agg <- aggregate(cbind(meanx=X,meany=Y)~ID, long, f, simplify=FALSE, na.action=na.pass);
> agg
ID meanx meany
1 1 1, 1 1, 1
2 2 2.000000000, 1.333333333 2.000000000, 1.333333333
3 3 1.00, 1.75 1.00, 1.75
4 4 2, 2 2, 2
5 5 2.000000000, 2.333333333 2.000000000, 2.333333333
6 6 2, 3 2, 3
7 7 3.0, 4.5 3.0, 4.5
8 8 2, 4 2, 4
9 9 3.0, 5.5 3.0, 5.5
10 10 3, 6 3, 6
> g <- function(x, i) if(x[1] <= i) x[2] else NA
> mapply(lapply, agg[2:3],list(g), c(2,1))
meanx meany
01 1 1
02 1.333333333 NA
03 1.75 1.75
04 2 NA
05 2.333333333 NA
06 3 NA
07 NA NA
08 4 NA
09 NA NA
10 NA NA
>f agg agg
我的意思是
1 1 1, 1 1, 1
2 2 2.000000000, 1.333333333 2.000000000, 1.333333333
3 3 1.00, 1.75 1.00, 1.75
4 4 2, 2 2, 2
5 5 2.000000000, 2.333333333 2.000000000, 2.333333333
6 6 2, 3 2, 3
7 7 3.0, 4.5 3.0, 4.5
8 8 2, 4 2, 4
9 9 3.0, 5.5 3.0, 5.5
10 10 3, 6 3, 6
>g这是一个基本的R解
我认为如果您首先使用长格式,这在概念上更容易,例如:
long <- reshape(df, idvar='ID', varying=colnames(df)[-1], timevar='t', sep='', direction='long')
然后,您可以根据您的描述相当自然地编写聚合函数。这一个匹配@snoram:
f <- function(x) if( sum(is.na(x)) > 2 ) NA else mean(x, na.rm=TRUE)
其中:
ID meanx meany
1 1 1.000000000 1.000000000
2 2 1.333333333 1.333333333
3 3 1.750000000 1.750000000
4 4 2.000000000 2.000000000
5 5 2.333333333 2.333333333
6 6 3.000000000 3.000000000
7 7 NA NA
8 8 4.000000000 4.000000000
9 9 NA NA
10 10 NA NA
然后,如果愿意,您可以cbind
将其返回到原始数据帧
这种方法的优点是,如果您也有X6、X7等,它应该可以轻松地处理它们
编辑:
重新阅读您的问题,您最好分别跟踪NAs的平均值和数量,然后进行后处理。下面是一个快速而肮脏的例子:
> f <- function(x) c(sum(is.na(x)), mean(x, na.rm=TRUE))
> agg <- aggregate(cbind(meanx=X,meany=Y)~ID, long, f, simplify=FALSE, na.action=na.pass);
> agg
ID meanx meany
1 1 1, 1 1, 1
2 2 2.000000000, 1.333333333 2.000000000, 1.333333333
3 3 1.00, 1.75 1.00, 1.75
4 4 2, 2 2, 2
5 5 2.000000000, 2.333333333 2.000000000, 2.333333333
6 6 2, 3 2, 3
7 7 3.0, 4.5 3.0, 4.5
8 8 2, 4 2, 4
9 9 3.0, 5.5 3.0, 5.5
10 10 3, 6 3, 6
> g <- function(x, i) if(x[1] <= i) x[2] else NA
> mapply(lapply, agg[2:3],list(g), c(2,1))
meanx meany
01 1 1
02 1.333333333 NA
03 1.75 1.75
04 2 NA
05 2.333333333 NA
06 3 NA
07 NA NA
08 4 NA
09 NA NA
10 NA NA
>f agg agg
我的意思是
1 1 1, 1 1, 1
2 2 2.000000000, 1.333333333 2.000000000, 1.333333333
3 3 1.00, 1.75 1.00, 1.75
4 4 2, 2 2, 2
5 5 2.000000000, 2.333333333 2.000000000, 2.333333333
6 6 2, 3 2, 3
7 7 3.0, 4.5 3.0, 4.5
8 8 2, 4 2, 4
9 9 3.0, 5.5 3.0, 5.5
10 10 3, 6 3, 6
>g您可以尝试类似于df$meanX=apply(df[,2:6],1,function(x)ifelse(sum(is.na(x))<2,mean(x,na.rm=TRUE),na))
的方法,在这里您可以将2替换为NAs的最大数量rowMeans
也可能会引起您的兴趣。它有点难以辨认,但应该非常快(特别是如果您转换为矩阵而不是使用数据帧):MeanX=round(rowMeans(df[,c(2:6)],na.rm=TRUE),2)*c(1,na)[(rowSums(is.na(df[,c(2:6)])>2)+1]
@Gregor-如果您在两条语句中执行,就可以避免混淆-df$MeanX=2]您可以尝试类似于df$MeanX=apply(df[,2:6],1,函数(x)ifelse(sum(is.na(x))<2,mean(x,na.rm=TRUE),na))
其中可以用最大数量的NAs替换2rowMeans
,您可能也感兴趣。它有点难以辨认,但应该非常快(特别是如果您转换为矩阵而不是使用数据帧):MeanX=round(rowMeans(df[,c(2:6)],na.rm=TRUE),2)*c(1,na)[