当前位置: 首页 > 知识库问答 >
问题:

复杂的公式内部安排

丌官高远
2023-03-14

我想得到一个通用公式来排列具有不同数量列的数据帧。

例如,在这种情况下,数据帧包含“类别1,类别2,点1,点2”:

  library(tidyverse)
  set.seed(1)
  nrows <- 20
  df <- tibble(
    other_text = sample(letters,
                        nrows, replace = TRUE),
    categ_1 = sample(c("A", "B"), nrows, replace = TRUE),
    categ_2 = sample(c("A", "B"), nrows, replace = TRUE),
    points_1 = sample(20:25, nrows, replace = TRUE),
    points_2 = sample(20:25, nrows, replace = TRUE),
  ) %>%
    rowwise() %>%
    mutate(total = sum(c_across(starts_with("points_")))) %>%
    ungroup()

以及要安排的公式:

df %>%
  arrange(
    desc(total),
    categ_1, categ_2,
    desc(points_1), desc(points_2)
  )

但df可以有更多的列:“categ_1,categ_2,categ_3,points_1,points_2,points_3”。因此,在这种情况下,公式应为:

df %>%
  mutate(
    categ_3 = sample(c("A", "B"), nrows, replace = TRUE),
    points_3 = sample(20:25, nrows, replace = TRUE),
  ) %>%
    rowwise() %>%
    mutate(total = sum(c_across(starts_with("points_")))) %>%
    ungroup() %>%
    arrange(
      desc(total),
      categ_1, categ_2, categ_3,
      desc(points_1), desc(points_2), desc(points_3)
    )

我尝试编写一个通用公式(跨使用):

  library(daff)

  daff::diff_data(
    df %>%
      arrange(
        desc(total),
        categ_1, categ_2,
        desc(points_1), desc(points_2)
      )
    ,
    df %>%
      arrange(
        desc(total),
        across(starts_with("categ_")),
        across(starts_with("points_"), desc)
      )
  )
#> Daff Comparison: ‘df %>% arrange(desc(total), categ_1, categ_2, desc(points_1), ’ ‘    desc(points_2))’ vs. ‘df %>% arrange(desc(total), across(starts_with("categ_")), across(starts_with("points_"), ’ ‘    desc))’
#>           A:A        B:B     ... E:E      F:F
#>       @@  other_text categ_1 ... points_2 total
#>       ... ...        ...     ... ...      ...
#> 10:9      z          A       ... 23       45
#> 9:10  :   v          A       ... 22       45
#> 11:11     s          B       ... 23       45
#>       ... ...        ...     ... ...      ...

arrange中似乎有一个bug:arrange只考虑参数,直到跨的第一个

我还尝试在case_when中编写条件,但找不到正确的语法:

  # not working
  df %>%
    arrange(
      across(everything(), ~ case_when(
        . == "total" ~ .,
        str_detect(., "categ_") ~ .,
        str_detect(., "points_") ~ desc(.),
        TRUE ~ 1
      )
      )
    )
#> Error in `arrange()`:
#> ! Problem with the implicit `transmute()` step.

在< code>arrange中编写该公式的一般方法是什么?(欢迎其他替代方案,但我更喜欢tidyverse解决方案。)

共有3个答案

罗昕
2023-03-14

您可以尝试将< code>arrange()中的所有内容打包到一个数据框中。看起来< code>arrange()做了一些代码操作,以特殊方式处理顶级< code>desc()调用,这与< code>across()创建的数据帧有不良交互。但是使用数据帧解包功能可以避免这种情况。

library(tidyverse)

set.seed(3)
nrows <- 20

df <- tibble(
  other_text = sample(letters, nrows, replace = TRUE),
  categ_1 = sample(c("A", "B"), nrows, replace = TRUE),
  categ_2 = sample(c("A", "B"), nrows, replace = TRUE),
  points_1 = sample(20:25, nrows, replace = TRUE),
  points_2 = sample(20:25, nrows, replace = TRUE),
) %>%
  rowwise() %>%
  mutate(total = sum(c_across(starts_with("points_")))) %>%
  ungroup()

identical(
  df %>%
    arrange(
      desc(total),
      categ_1, categ_2,
      desc(points_1), desc(points_2)
    ),
  df %>%
    arrange(
      tibble(
        desc(total),
        across(starts_with("categ_")),
        across(starts_with("points_"), desc)
      )
    )
)
#> [1] TRUE
古起运
2023-03-14

安装开发版本:

# remotes::install_github("tidyverse/dplyr")
library(tidyverse)

set.seed(144)
nrows <- 20
df <- tibble(
  other_text = sample(letters,
                      nrows, replace = FALSE),
  categ_1 = sample(c("A", "B"), nrows, replace = TRUE),
  categ_2 = sample(c("A", "B"), nrows, replace = TRUE),
  points_1 = sample(1:25, nrows, replace = FALSE),
  points_2 = sample(100:125, nrows, replace = FALSE),
) %>%
  rowwise() %>%
  mutate(total = sum(c_across(starts_with("points_")))) %>%
  ungroup()

out1 <- df %>%
  arrange(
    desc(total),
    categ_1, categ_2,
    desc(points_1), desc(points_2)
  )

out2 <- df %>%
  arrange(
    desc(total),
    across(starts_with("categ_")),
    across(starts_with("points_"), desc)
  )

daff::diff_data(out1, out2)
#> Daff Comparison: 'out1' vs. 'out2' 
#>      other_text categ_1 ...
充修能
2023-03-14

一种简单(排序)的解决方案是使用cur_column()来确定最终确定排序顺序的列名:

library(dplyr)
library(daff)

set.seed(32211)
nrows <- 20

df <- tibble(
   other_text = sample(letters,
                       nrows, replace = TRUE),
   categ_1 = sample(c("A", "B"), nrows, replace = TRUE),
   categ_2 = sample(c("A", "B"), nrows, replace = TRUE),
   points_1 = sample(20:25, nrows, replace = TRUE),
   points_2 = sample(20:25, nrows, replace = TRUE),
) %>%
   rowwise() %>%
   mutate(total = sum(c_across(starts_with("points_")))) %>%
   ungroup()
by_hand <- df %>%
   arrange(
      desc(total),
      categ_1, categ_2,
      desc(points_1), desc(points_2)
   )

with_across <- df %>%
   arrange(
      across(
         c(total, starts_with("categ_"), starts_with("points_")),
         .fns = function(x) {
            if (grepl("^total$|^points_.*$", cur_column()))
               desc(x)
            else
               x
         })
   )

diff_data(by_hand, with_across)
# Daff Comparison: ‘by_hand’ vs. ‘with_across’ 
#      other_text categ_1 categ_2 points_1 points_2 total
 类似资料:
  • 在Sonarqube5.5之前的版本中,为了考虑复杂性,有可能改变计算技术债务的方式,但在5.5之后,我看不出如何改变它。是否删除了此配置? 总之,在复杂的代码中,修复的成本比在简单的代码中要高得多。这里有一篇文章,您可以看到并比较两个相似的项目,它们的技术债务基于规模相似,但基于复杂性的技术债务却完全不同。此外,复盖面对这一措施也有影响;我认为,当你有足够的测试和覆盖,确保你没有破坏任何东西时,

  • “复杂小部件”允许用户与应用程序进行高级交互功能。 每个Complex小部件都从Widget类继承属性,Widget类继承UIObject的属性。 Sr.No. 小部件和描述 1 GWT UIObject类 此窗口小部件包含文本,不使用元素解释为HTML,从而使其以块布局显示。 2 GWT Widget类 此窗口小部件可以包含HTML文本,并使用元素显示html内容,使其以块布局显示。 复杂小部件

  • 上篇的标记算法中,谈到这个O(K)的算法是一个指数级复杂度的算法,其实对那道题目本身来说,K是固定的,既然不是输入,那也无所谓复杂度,之所以有O(K)这种说法,是把K当做一种输入了,这是看待输入的角度问题,倒不用深究。考虑一个更简化的算法(python代码,设输入n是正整数): def f(n): i = 0 while i < n: i += 1

  • 问题内容: 有人可以给我解释一下/ 内部 类有什么区别吗? 我知道内部类应尽可能避免(如本文所述)。 但是据我所知,使用或修饰符之间没有区别。 看一下这个例子: … … 所有这些都可以编译,并且无论我声明 还是都有效。 我想念什么?请指出一个使用或有所不同的情况。 谢谢。 问题答案: 该访问修饰符将限制从比在同一个包及其子类之外的其他类的访问。 在所示的示例中,和和将具有相同的效果,因为它们位于同

  • 复杂的表达式 当你有一个复杂的 if 子句的时候,你应该把它们提取出来赋给一个 BOOL 变量,这样可以让逻辑更清楚,而且让每个子句的意义体现出来。 BOOL nameContainsSwift = [sessionName containsString:@"Swift"]; BOOL isCurrentYear = [sessionDateCompontents year] == 2

  • 问题内容: 最佳实践是不公开对象(实体)的内部引用。 因此,如果一个对象具有一个类型的字段,那么例如该字段的获取程序应返回的不是原始日期,而是它的副本。 但是对于java.util.Date,有两种创建该副本的常用方法: 克隆: 通过构造函数复制 我的问题是,哪种方法更好,为什么? 问题答案: 如果绝对是a ,那么这两种方法都不会有任何区别。 如果实际的对象可能是一个 子类 的(如),那么我倒是希