我在下面有一个数据框。我需要找到行最小值和最大值,除了少数几列是字符。
df
x y z
1 1 1 a
2 2 5 b
3 7 4 c
我需要
df
x y z Min Max
1 1 1 a 1 1
2 2 5 b 2 5
3 7 4 c 4 7
另一种dplyr
可能性可能是:
df %>%
mutate(Max = do.call(pmax, select_if(., is.numeric)),
Min = do.call(pmin, select_if(., is.numeric)))
x y z Max Min
1 1 1 a 1 1
2 2 5 b 5 2
3 7 4 c 7 4
或者提议的变体是@G. Grothendieck:
df %>%
mutate(Min = pmin(!!!select_if(., is.numeric)),
Max = pmax(!!!select_if(., is.numeric)))
另一个基本的R解决方案。仅对带有数字的列进行子集化,然后在每行中使用apply
来获取带有range
的最小值和最大值。
cbind(df, t(apply(df[sapply(df, is.numeric)], 1, function(x)
setNames(range(x, na.rm = TRUE), c("min", "max")))))
# x y z min max
#1 1 1 a 1 1
#2 2 5 b 2 5
#3 7 4 c 4 7
1(这个单行不使用软件包:
transform(df, min = pmin(x, y), max = pmax(x, y))
给:
x y z min max
1 1 1 a 1 1
2 2 5 b 2 5
3 7 4 c 4 7
2(如果您有很多列并且不想将它们全部列出或确定自己哪些是数字,那么这也不使用包。
ix <- sapply(df, is.numeric)
transform(df, min = apply(df[ix], 1, min), max = apply(df[ix], 1, max))
如果您的实际数据具有 NA,并且如果您想在取最小值或最大值时忽略它们,则最小值、最大值、pmin 和 pmax 都采用可选的na.rm = TRUE
参数。
注意
Lines <- "x y z
1 1 1 a
2 2 5 b
3 7 4 c"
df <- read.table(text = Lines)
1(我们可以使用select_if
. 在这里,我们可以使用select_if
来选择数字列,然后使用pmin
,pmax
获取行min
并max
并将其与原始数据集绑定
library(dplyr)
library(purrr)
df %>%
select_if(is.numeric) %>%
transmute(Min = reduce(., pmin, na.rm = TRUE),
Max = reduce(., pmax, na.rm = TRUE)) %>%
bind_cols(df, .)
# x y z Min Max
#1 1 1 a 1 1
#2 2 5 b 2 5
#3 7 4 c 4 7
注意:在这里,我们只使用select_if
的单一表达式
2( 同样可以在base R
中完成(不使用软件包(
i1 <- names(which(sapply(df, is.numeric)))
df['Min'] <- do.call(pmin, c(df[i1], na.rm = TRUE))
df['Max'] <- do.call(pmax, c(df[i1], na.rm = TRUE))
此外,如评论中所述,这是通用选项。 如果只针对两列,则只需执行pmin(x, y)
或pmax(x,y)
操作是可能的,并且不会检查列是否numeric
,并且这不是通用解决方案
注意:此处提到的所有解决方案要么首先回答,要么来自OP的评论
数据
df <- structure(list(x = c(1L, 2L, 7L), y = c(1L, 5L, 4L), z = c("a",
"b", "c")), class = "data.frame", row.names = c("1", "2", "3"
))