从一行中的选定单元格中获取第一个非空值
Get the first non-null value from selected cells in a row
朋友们下午好!
我目前正在 R 中执行一些计算(df 显示在下方)。我的目标是在新列中显示每行选定单元格中的第一个非空值。
我的 df 是:
MD <- c(100, 200, 300, 400, 500)
liv <- c(0, 0, 1, 3, 4)
liv2 <- c(6, 2, 0, 4, 5)
liv3 <- c(1, 1, 1, 1, 1)
liv4 <- c(1, 0, 0, 3, 5)
liv5 <- c(0, 2, 7, 9, 10)
df <- data.frame(MD, liv, liv2, liv3, liv4, liv5)
我想显示(在名为“liv6”的列中)来自 5 个单元格的第一个非空值(给定数据,liv1 = 0、liv2 = 6、liv3 = 1、liv 4 = 1 和 liv5 = 1).结果应该是 6。并且应该对我的数据框中的每一行重复此计算..
我知道如何在 Python 中执行此操作,但在 R..
中不知道
非常感谢任何帮助!
dplyr
的一个选项可以是:
df %>%
rowwise() %>%
mutate(liv6 = with(rle(c_across(liv:liv5)), values[which.max(values != 0)]))
MD liv liv2 liv3 liv4 liv5 liv6
<dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 100 0 6 1 1 0 6
2 200 0 2 1 0 2 2
3 300 1 0 1 0 7 1
4 400 3 4 1 3 9 3
5 500 4 5 1 5 10 4
一个简单的基本 R 选项是跨相关列应用(我在这里排除了 MD
,您可以使用您想要的任何数据框子集样式),然后只取 [=14= 的第一个值] 该行的值。
df$liv6 <- apply(df[-1], 1, \(x) head(x[x > 0], 1))
df
#> MD liv liv2 liv3 liv4 liv5 liv6
#> 1 100 0 6 1 1 0 6
#> 2 200 0 2 1 0 2 2
#> 3 300 1 0 1 0 7 1
#> 4 400 3 4 1 3 9 3
#> 5 500 4 5 1 5 10 4
基础 R 解决方案:
df$liv6 <- apply(df[-1], 1, function(x) x[min(which(x != 0))])
输出
df
MD liv liv2 liv3 liv4 liv5 liv6
1 100 0 6 1 1 0 2
2 200 0 2 1 0 2 2
3 300 1 0 1 0 7 1
4 400 3 4 1 3 9 1
5 500 4 5 1 5 10 1
一种方法是使用 purrr::detect
检测每行的第一个 non-zero 元素。
我们定义一个函数,它接受一个数字向量(行)和 returns 一个布尔值,指示每个元素是否是 non-zero:
is_nonzero <- function(x) x != 0
我们使用此函数通过 purrr:detect
检测每行中的第一个 non-zero 元素
first_nonzero <- apply(df %>% dplyr::select(liv:liv5), 1, function(x) {
purrr::detect(x, is_nonzero, .dir = "forward")
})
我们终于创建了新列:
df$liv6 <- first_nonzero
因此,我们有
> df
MD liv liv2 liv3 liv4 liv5 liv6
100 0 6 1 1 0 6
200 0 2 1 0 2 2
300 1 0 1 0 7 1
400 3 4 1 3 9 3
500 4 5 1 5 10 4
另一个简单的解决方案是:
Reduce(function(x, y) ifelse(!x, y, x), df[, -1])
#[1] 6 2 1 3 4
这种方式应该非常有效,因为我们按列“扫描”,因为据推测,数据的列比行少得多。
Reduce
方法是一种更实用的简单形式,old-school,循环:
ans = df[, 2]
for(j in 3:ncol(df)) {
i = !ans
ans[i] = df[i, j]
}
ans
#[1] 6 2 1 3 4
朋友们下午好!
我目前正在 R 中执行一些计算(df 显示在下方)。我的目标是在新列中显示每行选定单元格中的第一个非空值。
我的 df 是:
MD <- c(100, 200, 300, 400, 500)
liv <- c(0, 0, 1, 3, 4)
liv2 <- c(6, 2, 0, 4, 5)
liv3 <- c(1, 1, 1, 1, 1)
liv4 <- c(1, 0, 0, 3, 5)
liv5 <- c(0, 2, 7, 9, 10)
df <- data.frame(MD, liv, liv2, liv3, liv4, liv5)
我想显示(在名为“liv6”的列中)来自 5 个单元格的第一个非空值(给定数据,liv1 = 0、liv2 = 6、liv3 = 1、liv 4 = 1 和 liv5 = 1).结果应该是 6。并且应该对我的数据框中的每一行重复此计算..
我知道如何在 Python 中执行此操作,但在 R..
中不知道非常感谢任何帮助!
dplyr
的一个选项可以是:
df %>%
rowwise() %>%
mutate(liv6 = with(rle(c_across(liv:liv5)), values[which.max(values != 0)]))
MD liv liv2 liv3 liv4 liv5 liv6
<dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 100 0 6 1 1 0 6
2 200 0 2 1 0 2 2
3 300 1 0 1 0 7 1
4 400 3 4 1 3 9 3
5 500 4 5 1 5 10 4
一个简单的基本 R 选项是跨相关列应用(我在这里排除了 MD
,您可以使用您想要的任何数据框子集样式),然后只取 [=14= 的第一个值] 该行的值。
df$liv6 <- apply(df[-1], 1, \(x) head(x[x > 0], 1))
df
#> MD liv liv2 liv3 liv4 liv5 liv6
#> 1 100 0 6 1 1 0 6
#> 2 200 0 2 1 0 2 2
#> 3 300 1 0 1 0 7 1
#> 4 400 3 4 1 3 9 3
#> 5 500 4 5 1 5 10 4
基础 R 解决方案:
df$liv6 <- apply(df[-1], 1, function(x) x[min(which(x != 0))])
输出
df
MD liv liv2 liv3 liv4 liv5 liv6
1 100 0 6 1 1 0 2
2 200 0 2 1 0 2 2
3 300 1 0 1 0 7 1
4 400 3 4 1 3 9 1
5 500 4 5 1 5 10 1
一种方法是使用 purrr::detect
检测每行的第一个 non-zero 元素。
我们定义一个函数,它接受一个数字向量(行)和 returns 一个布尔值,指示每个元素是否是 non-zero:
is_nonzero <- function(x) x != 0
我们使用此函数通过 purrr:detect
first_nonzero <- apply(df %>% dplyr::select(liv:liv5), 1, function(x) {
purrr::detect(x, is_nonzero, .dir = "forward")
})
我们终于创建了新列:
df$liv6 <- first_nonzero
因此,我们有
> df
MD liv liv2 liv3 liv4 liv5 liv6
100 0 6 1 1 0 6
200 0 2 1 0 2 2
300 1 0 1 0 7 1
400 3 4 1 3 9 3
500 4 5 1 5 10 4
另一个简单的解决方案是:
Reduce(function(x, y) ifelse(!x, y, x), df[, -1])
#[1] 6 2 1 3 4
这种方式应该非常有效,因为我们按列“扫描”,因为据推测,数据的列比行少得多。
Reduce
方法是一种更实用的简单形式,old-school,循环:
ans = df[, 2]
for(j in 3:ncol(df)) {
i = !ans
ans[i] = df[i, j]
}
ans
#[1] 6 2 1 3 4