对列求和,直到相邻列中的单元格为 NA,然后将每个列除以前一列

问题描述 投票:0回答:2

我正在尝试将数据表中的列相加,直到相邻列的值为 NA。例如,如果我有桌子:

日期 1 2 3
2022年7月1日 2 12 12
2022年8月1日 1 1 不适用
2022年9月1日 3 不适用 不适用

我只会将第 1 列中的第 2 行相加,因为第 2 列中的第 3 行是 NA,而第 2 列中的第 1 行是 NA。然后我会将这些列中的每一列除以前一列。我还想忽略日期。有没有一种方法可以在不进行硬编码的情况下做到这一点?这将是所需的结束行:

总计 3 12 12

我尝试使用“adorn_table”并排除 NA,但这似乎不起作用。

r
2个回答
2
投票

对于原来的问题,请尝试:

library(tidyverse)

# create made-up data
df <- tibble(
  x = c(2, 1, 3),
  y = c(12, 1, NA)
)

df |>
  filter(cumsum(is.na(y)) == 0) |>  # This will get rid of all rows starting from the first time when y is NA
  summarize(                        # add up the values of x
    s = sum(x)
  ) |>
  pull(s)                        

对于澄清的问题,我假设列数是任意的。

library(tidyverse)

# create a function to do the work
f <- function(.x, .y) {
  keep_rows <- cumsum(is.na(.y)) == 0
  sum(.x[keep_rows])
}

# create made-up data
df <- tibble(
  date = 1:3, # dates in your case, I'm keeping it simple
  x = c(2, 1, 3),
  y = c(12, 1, NA),
  z = c(12, NA, NA)
)

total_row <- map2(
 df |> select(x:z),  # select the columns being summed
 df |> select(y, z1 = z, z2 = z), # If you want the last column to depend on itself, you'll need to do something like this
  f
)

bind_rows(df |>
  mutate(date = as.character(date)), 
  c(date = "Total", total_row)
)

0
投票

1) 定义一个函数

sumToNA
,将 x 与 y 中第一个 NA 之前的位置相加。如果没有 NA,则将 x 全部相加。

然后将该函数映射到没有第 1 列的 DF 和没有前两列但最后一列的 DF 两次。没有使用任何封装。

sumToNA <- function(x, y) sum(x[!cummax(is.na(y))], na.rm = TRUE)
n <- ncol(DF)
rbind(DF, c("Total", mapply(sumToNA, DF[2:n], DF[c(3:n, n)])))
##         DATE 1    2    3
## 1 07/01/2022 2   12   12
## 2 08/01/2022 1    1 <NA>
## 3 09/01/2022 3 <NA> <NA>
## 4      Total 3   12   12

2) 定义一个函数

NAfwd
,它接受一个向量并返回它,但在第一个 NA 之后包含所有 NA,并将所有剩余的非 NA 转换为 0。然后将 DF[-1] 添加到处理后的 DF(没有第一个 NA)用
NAfwd
变换每列后,将两列和最后一列两次。然后使用
rowSums
对该行进行求和并将结果作为新行插入。

NAfwd <- \(z) 0 * Reduce(\(x, y) if (is.na(x)) x else y, z, acc = TRUE)

n <- ncol(DF)
rbind(DF, c("Total", colSums(DF[-1] + apply(DF[c(3:n,n)], 2, NAfwd), na.rm=TRUE)))
##         DATE 1    2    3
## 1 07/01/2022 2   12   12
## 2 08/01/2022 1    1 <NA>
## 3 09/01/2022 3 <NA> <NA>
## 4      Total 3   12   12

注意

DF <- data.frame(
  DATE = c("07/01/2022", "08/01/2022", "09/01/2022"),
  `1` = c(2L, 1L, 3L),
  `2` = c(12L, 1L, NA),
  `3` = c(12L, NA, NA),
  check.names = FALSE
)
© www.soinside.com 2019 - 2024. All rights reserved.