具有 NA 的多列的最小值和最大值
Min and Max across multiple columns with NAs
对于以下示例数据 dat
,有没有办法在处理 NA
时计算 min
和 max
。我的输入是:
dat <- read.table(text = "ID Name PM TP2 Sigma
1 Tim 1 2 3
2 Sam 0 NA 1
3 Pam 2 1 NA
4 Ali 1 0 2
NA NA NA NA NA
6 Tim 2 0 7", header = TRUE)
我需要的输出是:
ID Name PM TP2 Sigma Min Max
1 Tim 1 2 3 1 3
2 Sam 0 NA 1 0 1
3 Pam 2 1 NA 1 2
4 Ali 1 0 2 0 2
NA NA NA NA NA NA NA
6 Tim 2 0 7 0 7
我的努力
1- 我看过类似的帖子,但其中 none 讨论了列中所有条目都是 NA
的问题,例如 Get the min of two columns
基于此,我尝试了 pmin()
和 pmax()
,但它们对我不起作用。
2-另一个类似的问题是minimum (or maximum) value of each row across multiple columns。同样,无需处理 NA
s.
3- 最后,这个问题 minimum (or maximum) value of each row across multiple columns 讨论了 NA
但并不是列中的所有元素都有缺失值。
4- 另外,一些解决方案要求手动输入要排除的列列表,我的原始数据相当 wide
,我想有一个更简单的解决方案,我可以表达按数字而不是名称列。
部分解
我尝试了以下解决方案,但 Min
列最终具有 Inf
,而 Max
列最终具有 -Inf
.
dat$min = apply(dat[,c(2:4)], 1, min, na.rm = TRUE)
dat$max = apply(dat[,c(2:4)], 1, max, na.rm = TRUE)
我可以手动删除 Inf
,方法如下:
dat$min[is.infinite(dat$min)] = NA
但我想知道是否有更好的方法来实现我想要的结果?任何建议将不胜感激。
感谢您的宝贵时间。
以下解决方案似乎适用于 transform()
函数:
dat <- transform(dat, min = pmin(PM, TP2, Sigma))
dat <- transform(dat, max = pmin(PM, TP2, Sigma))
没有使用transform()
函数,数据好像乱七八糟。此外,上述命令要求明确写入所有列名。我不明白为什么写一个像下面这样的简短版本会失败。
pmin(dat[,2:4])) or
pmax(dat[,2:4]))
我发布了我能想到的唯一解决方案,以防其他人遇到类似问题。
您可以使用 hablar
的 min_
和 max_
函数,其中 returns NA
如果所有值都是 NA
。
library(dplyr)
library(hablar)
dat %>%
rowwise() %>%
mutate(min = min_(c_across(-ID)),
max = max_(c_across(-ID)))
您也可以将其与 apply
-
一起使用
cbind(dat, t(apply(dat[-1], 1, function(x) c(min = min_(x), max = max_(x)))))
# ID PM TP2 Sigma min max
#1 1 1 2 3 1 3
#2 2 0 NA 1 0 1
#3 3 2 1 NA 1 2
#4 4 1 0 2 0 2
#5 NA NA NA NA NA NA
#6 5 2 0 7 0 7
可能是将 pmin
和 pmax
与 do.call
:
一起使用
dat$min <- do.call(pmin, c(dat[,c(3:5)], na.rm=TRUE))
dat$max <- do.call(pmax, c(dat[,c(3:5)], na.rm=TRUE))
dat
# ID Name PM TP2 Sigma min max
#1 1 Tim 1 2 3 1 3
#2 2 Sam 0 NA 1 0 1
#3 3 Pam 2 1 NA 1 2
#4 4 Ali 1 0 2 0 2
#5 NA <NA> NA NA NA NA NA
#6 6 Tim 2 0 7 0 7
我会用 data.table 来完成这个任务。我使用 rowSums 计算带有 na 的行数,并将其与总列数进行比较。我只是在 dat.new 中使用了至少有一个非 NA 值的所有列。然后你可以像往常一样使用na.rm=T。
希望这段小代码对您有所帮助。
library(data.table)
#your data
dat <- read.table(text = "ID PM TP2 Sigma
1 1 2 3
2 0 NA 1
3 2 1 NA
4 1 0 2
NA NA NA NA
5 2 0 7", header = TRUE)
#generate data.table and add id
dat <- data.table(dat)
number.cols <- dim(dat)[2] #4
dat[,id:=c(1:dim(dat)[1])]
# > dat
# ID PM TP2 Sigma id
# 1: 1 1 2 3 1
# 2: 2 0 NA 1 2
# 3: 3 2 1 NA 3
# 4: 4 1 0 2 4
# 5: NA NA NA NA 5
# 6: 5 2 0 7 6
#use new data.table to select all rows with at least one nonNA value
dat.new <- dat[rowSums(is.na(dat))<number.cols,]
dat.new[, MINv:=min(.SD, na.rm=T), by=id]
dat.new[, MAXv:=max(.SD, na.rm=T), by=id]
#if you need it merged to the old data
dat <- merge(dat, dat.new[,.(id,MINv,MAXv)], by="id")
对于以下示例数据 dat
,有没有办法在处理 NA
时计算 min
和 max
。我的输入是:
dat <- read.table(text = "ID Name PM TP2 Sigma
1 Tim 1 2 3
2 Sam 0 NA 1
3 Pam 2 1 NA
4 Ali 1 0 2
NA NA NA NA NA
6 Tim 2 0 7", header = TRUE)
我需要的输出是:
ID Name PM TP2 Sigma Min Max
1 Tim 1 2 3 1 3
2 Sam 0 NA 1 0 1
3 Pam 2 1 NA 1 2
4 Ali 1 0 2 0 2
NA NA NA NA NA NA NA
6 Tim 2 0 7 0 7
我的努力
1- 我看过类似的帖子,但其中 none 讨论了列中所有条目都是 NA
的问题,例如 Get the min of two columns
基于此,我尝试了 pmin()
和 pmax()
,但它们对我不起作用。
2-另一个类似的问题是minimum (or maximum) value of each row across multiple columns。同样,无需处理 NA
s.
3- 最后,这个问题 minimum (or maximum) value of each row across multiple columns 讨论了 NA
但并不是列中的所有元素都有缺失值。
4- 另外,一些解决方案要求手动输入要排除的列列表,我的原始数据相当 wide
,我想有一个更简单的解决方案,我可以表达按数字而不是名称列。
部分解
我尝试了以下解决方案,但 Min
列最终具有 Inf
,而 Max
列最终具有 -Inf
.
dat$min = apply(dat[,c(2:4)], 1, min, na.rm = TRUE)
dat$max = apply(dat[,c(2:4)], 1, max, na.rm = TRUE)
我可以手动删除 Inf
,方法如下:
dat$min[is.infinite(dat$min)] = NA
但我想知道是否有更好的方法来实现我想要的结果?任何建议将不胜感激。
感谢您的宝贵时间。
以下解决方案似乎适用于 transform()
函数:
dat <- transform(dat, min = pmin(PM, TP2, Sigma))
dat <- transform(dat, max = pmin(PM, TP2, Sigma))
没有使用transform()
函数,数据好像乱七八糟。此外,上述命令要求明确写入所有列名。我不明白为什么写一个像下面这样的简短版本会失败。
pmin(dat[,2:4])) or
pmax(dat[,2:4]))
我发布了我能想到的唯一解决方案,以防其他人遇到类似问题。
您可以使用 hablar
的 min_
和 max_
函数,其中 returns NA
如果所有值都是 NA
。
library(dplyr)
library(hablar)
dat %>%
rowwise() %>%
mutate(min = min_(c_across(-ID)),
max = max_(c_across(-ID)))
您也可以将其与 apply
-
cbind(dat, t(apply(dat[-1], 1, function(x) c(min = min_(x), max = max_(x)))))
# ID PM TP2 Sigma min max
#1 1 1 2 3 1 3
#2 2 0 NA 1 0 1
#3 3 2 1 NA 1 2
#4 4 1 0 2 0 2
#5 NA NA NA NA NA NA
#6 5 2 0 7 0 7
可能是将 pmin
和 pmax
与 do.call
:
dat$min <- do.call(pmin, c(dat[,c(3:5)], na.rm=TRUE))
dat$max <- do.call(pmax, c(dat[,c(3:5)], na.rm=TRUE))
dat
# ID Name PM TP2 Sigma min max
#1 1 Tim 1 2 3 1 3
#2 2 Sam 0 NA 1 0 1
#3 3 Pam 2 1 NA 1 2
#4 4 Ali 1 0 2 0 2
#5 NA <NA> NA NA NA NA NA
#6 6 Tim 2 0 7 0 7
我会用 data.table 来完成这个任务。我使用 rowSums 计算带有 na 的行数,并将其与总列数进行比较。我只是在 dat.new 中使用了至少有一个非 NA 值的所有列。然后你可以像往常一样使用na.rm=T。
希望这段小代码对您有所帮助。
library(data.table)
#your data
dat <- read.table(text = "ID PM TP2 Sigma
1 1 2 3
2 0 NA 1
3 2 1 NA
4 1 0 2
NA NA NA NA
5 2 0 7", header = TRUE)
#generate data.table and add id
dat <- data.table(dat)
number.cols <- dim(dat)[2] #4
dat[,id:=c(1:dim(dat)[1])]
# > dat
# ID PM TP2 Sigma id
# 1: 1 1 2 3 1
# 2: 2 0 NA 1 2
# 3: 3 2 1 NA 3
# 4: 4 1 0 2 4
# 5: NA NA NA NA 5
# 6: 5 2 0 7 6
#use new data.table to select all rows with at least one nonNA value
dat.new <- dat[rowSums(is.na(dat))<number.cols,]
dat.new[, MINv:=min(.SD, na.rm=T), by=id]
dat.new[, MAXv:=max(.SD, na.rm=T), by=id]
#if you need it merged to the old data
dat <- merge(dat, dat.new[,.(id,MINv,MAXv)], by="id")