使用 dplyr 在 data.frame 中查找逐行最小正非零数
Posted
技术标签:
【中文标题】使用 dplyr 在 data.frame 中查找逐行最小正非零数【英文标题】:Find row-wise minimum positive non-zero number in data.frame using dplyr 【发布时间】:2019-02-27 09:42:51 【问题描述】:给定一个数字数据框
A <- c(1.1, 3.0, 2.0, 4.0, 0.0, 1.3)
B <- c(0.2, 1.0, 2.4, 1.1, 1.3, 0.0)
C <- c(5.2, 1.3, 3.7, 1.7, 1.3, 1.0)
data <- data.frame(A, B, C) %>% as_tibble()
如何创建包含按行最小正非零数的另一列(如果可能,使用 dplyr)以获得以下数据帧?
## A tibble: 6 x 4
# A B C posmin
# <dbl> <dbl> <dbl> <dbl>
#1 1.1 0.2 5.2 0.2
#2 3 1 1.3 1
#3 2 0 3.7 2
#4 4 1.1 1.7 1.1
#5 0 1.3 1.3 1.3
#6 1.3 0 1 1
什么是简洁,几乎可以完成工作的是
data %>% mutate(posmin = pmin(A, B, C))
但是有两个问题:
我的真实数据框有更多列(A 到 Z),我无法调用pmin(A:Z)
pmin
计算行最小值
是否有类似pminpos
的东西,如果没有,我该如何创建它以便可以像上面代码中的pmin
一样调用它?以及如何在不传递以逗号分隔的名称列表的情况下指定许多连续的列?
非常感谢。
编辑:我显然没有强调这一点,我正在寻找非零正数,即严格大于 > 0 的数字。因此寻求-after 第 5 行和第 6 行的值不为零。
【问题讨论】:
第 5 行和第 6 行的最小值应该为 0,不是吗? @JilberUrbina 我正在寻找严格大于零的数字。很抱歉含糊不清 - 我调整了问题的措辞。 【参考方案1】:一种选择是将列名转换为符号,然后计算 (!!!
)
library(dplyr)
data %>%
mutate_all(funs(replace(., .==0, NA))) %>%
transmute(posmin = pmin(!!! rlang::syms(names(.)), na.rm = TRUE)) %>%
bind_cols(data, .)
# A tibble: 6 x 4
# A B C posmin
# <dbl> <dbl> <dbl> <dbl>
#1 1.1 0.2 5.2 0.2
#2 3 1 1.3 1
#3 2 2.4 3.7 2
#4 4 1.1 1.7 1.1
#5 0 1.3 1.3 1.3
#6 1.3 0 1 1
或使用map/reduce
map(data, na_if, 0) %>%
reduce(pmin, na.rm = TRUE) %>%
bind_cols(data, posmin = .)
或者不使用任何外部包,我们可以在do.call
内单行调用pmin
data$posmin <- do.call(pmin, c(NA^ (data == 0) * data, na.rm = TRUE))
data$posmin
#[1] 0.2 1.0 2.0 1.1 1.3 1.0
或者基于@Moody_Mudskipper的cmets,而不是将0分配给NA
,而是将其更改为更大的值(Inf
),然后使用pmin
data$posmin <- do.call(pmin, '[<-'(data, data <=0, value=Inf))
【讨论】:
我认为 OP 只寻找 > 0 的最小值,即类似于data$posmin <- do.call(pmin, c(replace(data, data == 0, NA), na.rm = TRUE))
@markus 没错。我正在寻找严格大于零的值
另一种类似的方式是data$posmin <- do.call(pmin, '[<-'(data, data <=0, value=Inf))
@Moody_Mudskipper 谢谢,这是一个紧凑的选择【参考方案2】:
apply
适合这里:
> data$posmin <- apply(data, 1, function(x) min(x[x>0]))
> data
# A tibble: 6 x 4
A B C posmin
<dbl> <dbl> <dbl> <dbl>
1 1.1 0.2 5.2 0.2
2 3 1 1.3 1
3 2 2.4 3.7 2
4 4 1.1 1.7 1.1
5 0 1.3 1.3 1.3
6 1.3 0 1 1
【讨论】:
【参考方案3】:您可以使用invoke
和na_if
,正如@markus 所评论的那样
data %>%
mutate(posmin = invoke(pmin, na_if(., 0), na.rm = TRUE))
# A tibble: 6 x 4
A B C posmin
<dbl> <dbl> <dbl> <dbl>
1 1.1 0.2 5.2 0.2
2 3 1 1.3 1
3 2 2.4 3.7 2
4 4 1.1 1.7 1.1
5 0 1.3 1.3 1.3
6 1.3 0 1 1
【讨论】:
或者data %>% mutate(posmin = invoke(pmin, na_if(., 0), na.rm = TRUE))
。【参考方案4】:
这是一个类似于apply()
的tidyverse 解决方案,使用purrr
包:
data %>% mutate(posmin = pmap(data, min))
【讨论】:
以上是关于使用 dplyr 在 data.frame 中查找逐行最小正非零数的主要内容,如果未能解决你的问题,请参考以下文章
覆盖使用 Dplyr - R 过滤的 data.frame 上的值
当我不知道 data.frame 中的列名时,当我使用 dplyr mutate 函数时
R dplyr:来自外部查找表的 summarise_each?