计算行方向最大值的问题

时间:2017-11-26 20:22:09

标签: r dplyr

假设我下面有一个tibble数据,我想要做的是计算(x 2x 3)的最大值然后减去x 1,其中x可以是或b。在我的真实数据中,我有超过3列,所以像2:n(例如,2:3)这样的东西会很棒。尝试了很多东西,似乎没有按照我的要求工作,仍然在努力处理字符串与列名称的事情。

dat <- tibble(`a 1` = c(0, 0, 0), `a 2` = 1:3, `a 3` = 3:1, 
`b 1` = rep(1, 3), `b 2` = 4:6, `b 3` = 6:4)


foo <- function(x = 'a')
{
  ???
}

最终结果:

if x == `a`

c(3, 2, 3)

if x == `b`

c(5, 4, 5)

1 个答案:

答案 0 :(得分:4)

解决方案1 ​​

此解决方案仅使用基础R.想法是定义一个函数(max_minus_first)来计算答案。 max_minus_first函数有两个参数。第一个参数dat是用于分析的数据框,其格式与提供的OP相同。 group是分析组的名称。最终产品是一个答案的矢量。

max_minus_first <- function(dat, group){
  # Get all column names with starting string "group"
  col_names <-  colnames(dat)
  dat2 <- dat[, col_names[grepl(paste0("^", group), col_names)]]

  # Get the maximum values from all columns except the first column
  max_value <- apply(dat2[, -1], 1, max, na.rm = TRUE)

  # Calculate max_value minus the values from the first column
  final_value <- max_value - unlist(dat2[, 1], use.names = FALSE)

  return(final_value)
}

max_minus_first(dat, "a")
# [1] 3 2 3

max_minus_first(dat, "b")
# [1] 5 4 5

解决方案2

使用tidyverse的解决方案。最终产品(dat2)是tibble,其中包含每个组的输出(ab,...)

library(tidyverse)

dat2 <- dat %>%
  rowid_to_column() %>%
  gather(Column, Value, -rowid, -ends_with(" 1")) %>%
  separate(Column, into = c("Group", "Column_Number")) %>%
  gather(Column_1, Value_1, ends_with(" 1")) %>%
  separate(Column_1, into = c("Group_1", "Column_Number_1")) %>%
  filter(Group == Group_1) %>%
  group_by(rowid, Group, Value_1) %>%
  summarise(Value = max(Value, na.rm = TRUE)) %>%
  mutate(Final = Value - Value_1) %>%
  ungroup() %>%
  select(-starts_with("Value")) %>%
  spread(Group, Final)
dat2
# # A tibble: 3 x 3
#   rowid     a     b
# * <int> <dbl> <dbl>
# 1     1     3     5
# 2     2     2     4
# 3     3     3     5

解释

  1. rowid_to_column()来自tibble包,是一种基于行ID创建新列的方法。
  2. gather来自tidyr包,用于将数据框从宽格式转换为长格式。我使用gather两次,因为每个组的第一列与同一组中的其他列不同。 ends_with(" 1")是来自select的{​​{1}}辅助函数,它选择名称以dplyr结尾的列。请注意" 1"中的空格非常重要,因为如果存在此类列," 1"可能会选择其他列,例如"1"
  3. a 11来自separate包,将列分为两列。我用它来分隔每个tidyr中的Group名称和列号。
  4. Group将使用filter(Group == Group_1)过滤行。
  5. Group == Group_1然后group_by(rowid, Group, Value_1)确保计算每个summarise(Value = max(Value, na.rm = TRUE))的最大值。
  6. Group用于计算每个mutate(Final = Value - Value_1)的最大值与第一列的值之间的差值。结果存储在Group列中。
  7. Final会删除名称以select(-starts_with("Value"))开头的所有列。
  8. 来自"Value"包的
  9. spread将数据框从长格式转换为宽格式。
  10. 解决方案3

    另一个tidyr解决方案,类似于解决方案2.它使用tidyverse对每个do进行操作,从而使代码更简洁。

    Group