【问题标题】:Finding if the values in one column are within the range of several other columns查找一列中的值是否在其他几列的范围内
【发布时间】:2021-06-09 22:11:39
【问题描述】:

我正在寻找一种简单的方法来确定列中的值是否在其他列中的值范围内。

我的输入如下所示:

ID  "Q1 Comm - 01 Scope Thesis" "Q1 Comm - 02 Scope Project" "Q1 Comm - 03 Learn Intern"    "Q1 Comm - 04 Biography"    "Q1 Comm - Overall Plan"
10   NA                          NA                           4                              NA      4
31   2                           NA                           NA                             NA      2
225  0                           NA                           NA                             NA      1
243  NA                          2                            NA                             1       0
310  NA                          2                            NA                             1       NA

对于每个唯一的ID,我有兴趣确定Q1 Comm - Overall Plan 列何时是:

1 - Below 所有其他列的min(),或

2 - Above 所有其他列的max(),或

3 - Within 所有其他列的范围

完整的列列表(连同overall 列)如下:

"Q1 Comm - 01 Scope Thesis"
"Q1 Comm - 02 Scope Project"
"Q1 Comm - 03 Learn Intern"
"Q1 Comm - 04 Biography"
"Q1 Comm - 05 Exhibit"
"Q1 Comm - 06 Social Act"
"Q1 Comm - 07 Post Project"
"Q1 Comm - 08 Learn Plant"
"Q1 Comm - 09 Study Narrate"
"Q1 Comm - 10 Learn Participate"
"Q1 Comm - 11 Write 1"
"Q1 Comm - 12 Read 2"
"Q1 Comm - Overall Plan"

我需要的输出是这样的:

ID  "Q1 Comm - 01 Scope Thesis" "Q1 Comm - 02 Scope Project" "Q1 Comm - 03 Learn Intern"    "Q1 Comm - 04 Biography"    "Q1 Comm - Overall Plan" "Q1_check"
10   NA                          NA                           4                              NA      4 "within"
31   2                           NA                           NA                             NA      2 "within"
225  0                           NA                           NA                             NA      1 "above"
243  NA                          2                            NA                             1       0 "below"
310  NA                          2                            NA                             1       NA NA

我的数据框df 的 dput() 如下。

dput(df)

structure(list(ID = c(10L, 31L, 225L, 243L), Q1.Comm...01.Scope.Thesis = c(NA, 
2L, 0L, NA), Q1.Comm...02.Scope.Project = c(NA, NA, NA, 2L), 
    Q1.Comm...03.Learn.Intern = c(4L, NA, NA, NA), Q1.Comm...04.Biography = c(NA, 
    NA, NA, 1L), Q1.Comm...Overall.Plan = c(4L, 1L, 2L, 
    NA), X = c(NA, NA, NA, NA), X.1 = c(NA, NA, NA, NA), X.2 = c(NA, 
    NA, NA, NA)), class = "data.frame", row.names = c(NA, -4L
))

注意:

我曾在这里Finding if a value is within the range of other columns 提出过这个问题,但示例过于简单,没有一个解决方案适合我。

问题太长了,因此,为了清楚起见,我将其作为一个新问题发布。

感谢您在这篇文章中的时间和帮助。

【问题讨论】:

  • 您发布的dput 与您的预期结果不符。
  • 谢谢,我已经更新了。它实际上包含与我的原始数据相似的列列表。
  • @Sandy,为一个 Q 做这件事相当容易,但同时为几个 Q 做需要思考。 :) 我应该为这个 dput 发布答案吗?很抱歉,对于您的实际要求,这个问题再次过于简化!

标签: r string range comparison multiple-columns


【解决方案1】:
library(purrr)
library(data.table)

needed_cols <- setdiff(names(df), c("ID", "Q1.Comm...Overall.Plan"))

setDT(df)[, c("min", "max") := transpose(pmap(.SD, range, na.rm = TRUE)), .SDcols = needed_cols]
df[, Q1_check := fcase(
    is.na(`Q1.Comm...Overall.Plan`), NA_character_,
    `Q1.Comm...Overall.Plan` < min, "below",
    `Q1.Comm...Overall.Plan` > max, "above",
    default = "within"
  )
]
df[, c("max", "min") := NULL]

【讨论】:

  • 非常感谢@det。它似乎适用于给定的df。一个快速的问题,它可以在 for 循环中使用,因为我有其他变量以 Q2 等名称开头,然后是另一组以 Q3 等名称开头的变量。我当然可以运行你的整洁脚本 3 次或更多。但是只是想知道它是否可以更新?
  • 您建议的解决方案也适用于我的原始数据集。我只需要分别对每个问题重复一遍。我会接受的。谢谢!
  • 可以,但我不知道你想在循环内做什么。甚至可以在没有循环的情况下做到这一点。
  • 我已在您的其他问题中添加了答案,希望对您的循环有所帮助(此问题与 Q2 无关)。
【解决方案2】:

您可以尝试使用 rowwisec_across 进行类似操作:

library(dplyr)
df %>%
  rowwise %>%
  summarise(ID = ID,
            Max = `Q1.Comm...Overall.Plan` > max(c_across(-c(ID,`Q1.Comm...Overall.Plan`)),na.rm = TRUE),
            Min = `Q1.Comm...Overall.Plan` < min(c_across(-c(ID,`Q1.Comm...Overall.Plan`)),na.rm = TRUE),
            Range = `Q1.Comm...Overall.Plan` >= range(c_across(-c(ID,`Q1.Comm...Overall.Plan`)),na.rm = TRUE)[1] &
                    `Q1.Comm...Overall.Plan` <= range(c_across(-c(ID,`Q1.Comm...Overall.Plan`)),na.rm = TRUE)[2]) %>%
  mutate(Result = case_when(Max ~ "above",
                            Min ~ "below",
                            Range ~ "within",
                            TRUE ~ NA_character_))
# A tibble: 4 x 5
     ID Max   Min   Range Result
  <int> <lgl> <lgl> <lgl> <chr> 
1    10 FALSE FALSE TRUE  within
2    31 FALSE FALSE TRUE  within
3   225 TRUE  FALSE FALSE above 
4   243 NA    NA    NA    NA    

您可以将summarise 更改为mutate 以保留原始列和/或select 以删除它们。

请参阅dplyr rowwise tutorial 了解更多信息。

【讨论】:

  • 感谢您发布解决方案并提供有关 rowwise 教程的信息。
【解决方案3】:

我已经修改了您的 dput 以适应您在链接问题中讨论的要求。我想这会对你有所帮助。我使用了janitor::clean_names(),建议您在继续之前使用它,以便清理您的列名。

所以修改后的输出是

df <- structure(list(id = c(10L, 31L, 225L, 243L), q1_comm_01_scope_thesis = c(NA, 
2L, 0L, NA), q1_comm_02_scope_project = c(NA, NA, NA, 2L), q1_comm_03_learn_intern = c(4L, 
NA, NA, NA), q1_comm_04_biography = c(NA, NA, NA, 1L), q1_comm_overall_plan = c(4L, 
1L, 2L, NA), q2_comm_01_scope_thesis = c(NA, 4, 0, NA), q2_comm_02_scope_project = c(NA, 
NA, NA, 4), q2_comm_03_learn_intern = c(8, NA, NA, NA), q2_comm_04_biography = c(NA, 
NA, NA, 2), q2_comm_overall_plan = c(8, 2, 4, NA)), row.names = c(NA, 
-4L), class = "data.frame")

df
   id q1_comm_01_scope_thesis q1_comm_02_scope_project q1_comm_03_learn_intern q1_comm_04_biography q1_comm_overall_plan q2_comm_01_scope_thesis
1  10                      NA                       NA                       4                   NA                    4                      NA
2  31                       2                       NA                      NA                   NA                    1                       4
3 225                       0                       NA                      NA                   NA                    2                       0
4 243                      NA                        2                      NA                    1                   NA                      NA
  q2_comm_02_scope_project q2_comm_03_learn_intern q2_comm_04_biography q2_comm_overall_plan
1                       NA                       8                   NA                    8
2                       NA                      NA                   NA                    2
3                       NA                      NA                   NA                    4
4                        4                      NA                    2                   NA

现在按照建议进行。 您必须修改 cur_data() 内的 [-5] 以适应您的要求(根据整体列的相对位置,我认为在您的情况下为 9)

library(tidyverse)

split.default(df[-1], gsub('(q\\d*)(.*)', '\\1', names(df[-1]), perl = T)) %>%
  map(., ~ .x %>% bind_cols('id' = df$id) %>%
        group_by(id) %>%
        mutate(across(ends_with('_overall_plan'), ~ case_when(. < min(cur_data()[-5], na.rm = T) ~ 'below',
                                                              . > max(cur_data()[-5], na.rm = T) ~ 'above',
                                                              is.na(.) ~ NA_character_,
                                                              TRUE ~ 'within'),
                      .names = '{str_remove(.col,"_comm_overall_plan")}_check'))
        ) %>%
  reduce(left_join, by = 'id')

# A tibble: 4 x 13
# Groups:   id [4]
  q1_comm_01_scop~ q1_comm_02_scop~ q1_comm_03_lear~ q1_comm_04_biog~ q1_comm_overall~    id q1_check q2_comm_01_scop~ q2_comm_02_scop~ q2_comm_03_lear~ q2_comm_04_biog~
             <int>            <int>            <int>            <int>            <int> <int> <chr>               <dbl>            <dbl>            <dbl>            <dbl>
1               NA               NA                4               NA                4    10 within                 NA               NA                8               NA
2                2               NA               NA               NA                1    31 below                   4               NA               NA               NA
3                0               NA               NA               NA                2   225 above                   0               NA               NA               NA
4               NA                2               NA                1               NA   243 NA                     NA                4               NA                2
# ... with 2 more variables: q2_comm_overall_plan <dbl>, q2_check <chr>

【讨论】:

  • 感谢您告诉我有关 janitor() 软件包的信息。但是,该解决方案不适用于我的原始数据集。
  • 这就是为什么我要求您发布完整数据集的几行(可能是 4 行)。再告诉我一件事,每一行的 ID 是唯一的吗?
  • 是的,ID 是唯一的。我已将数据预处理为 wide 格式,其中与 ID 相关的所有信息都在它们自己的行中。
猜你喜欢
  • 2021-08-26
  • 1970-01-01
  • 2019-03-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多