【问题标题】:Looping and concatenating based on a condition in R基于R中的条件循环和连接
【发布时间】:2019-11-26 17:09:42
【问题描述】:

我是 R 新手,仍在为循环而苦恼。

我正在尝试创建一个循环,其中基于条件 (variable_4 == 1),它将连接 variable_5 的内容,用逗号分隔。

data1 <- data.frame(
  ID = c(123:127),
  agent_1 = c('James', 'Lucas','Yousef', 'Kyle', 'Marisa'),
  agent_2 = c('Sophie', 'Danielle', 'Noah', 'Alex', 'Marcus'),
  agent_3 = c('Justine', 'Adrienne', 'Olivia', 'Janice', 'Josephine'),
  Flag_1 = c(1,0,1,0,1),
  Flag_2 = c(0,1,0,0,1),
  Flag_3 = c(1,0,1,0,1)
)

data1$new_var<- ""

    for(i in 2:10){

      variable_4 <- paste0("flag_", i)
      variable_5 <- paste0("agent_", i)

      data1 <- data1 %>%
        mutate(!! new_var = case_when(variable_4 == 1,paste(new_var, variable_5, sep=",")))
    }

我在上一步中创建了 new_var,因为代码给了我一个找不到变量的错误。理想情况下,循环会累积 variable_5 的内容,前提是 variable_4 等于 1 并且结果是大字符串,用逗号分隔。

循环只会在新变量中粘贴标志 = 1 的代理的名称。如果 Flag_1=1,则将代理的名称粘贴到 new_var 中,如果不是,则忽略。如果flag_2 =1,则连接新var中的agent名称,用逗号分隔,如果不是,则忽略...

【问题讨论】:

  • 我认为您需要更清楚地了解您要测试的条件。您是否尝试测试迭代值 i == 1 然后在 new_var 中创建串联,因为 variable_4 将始终属于“flag_1”、“flag_2”等类型 - 它不会像 1,2 那样本身是一个数字,3 等
  • 如果您创建一些示例数据(未给出data1)并尝试获得所需的输出,您的问题会更加清晰
  • 嗨,如果我的问题不够清楚,我很抱歉。我有一个称为代理的变量。假设变量的内容是agent_1,agent_2,agent_3,agent_4...agent_10。假设标志(变量 4 )仅对 agent_1、agent_4、agent_7 等于 1。该循环会将代理变量的内容保存在 new_var 中,例如该行的 new_var ="agent_1,agent_4, agent_7"。不会添加其他代理,因为标志不是 1。这有意义吗?
  • 我添加了一张图片,希望对您有帮助?
  • 是的,这张图片现在让你的预期输出清晰了。我将编辑以添加 data1 的数据,以使您的示例可重现。

标签: r loops string-concatenation


【解决方案1】:

您不需要为此使用循环。数据是wide 格式的,这使得它更难,但是如果我们转换成long 格式,我们可以很容易地找到一个矢量化的解决方案,而不是使用循环。

pivot_longer 函数在这里很有用,它需要 tidyr 版本 >= 1.0.0。

library(tidyr)
library(dplyr)

pivot_longer(data1, 
             cols = -ID, 
             names_to = c(".value", "group"),
             names_sep = "_") %>%
  group_by(ID) %>%
  mutate(new_var = paste0(agent[Flag==1], collapse = ',')) %>%
  pivot_wider(names_from = c("group"),
              values_from = c('agent', 'Flag'),
              names_sep = '_') %>%
  ungroup() %>%
  select(ID, starts_with('agent'), starts_with('Flag'), new_var)

## A tibble: 5 x 8
#     ID agent_1 agent_2  agent_3   Flag_1 Flag_2 Flag_3 new_var                
#  <int> <chr>   <chr>    <chr>     <chr>  <chr>  <chr>  <chr>                  
#1   123 James   Sophie   Justine   1      0      1      James,Justine          
#2   124 Lucas   Danielle Adrienne  0      1      0      Danielle               
#3   125 Yousef  Noah     Olivia    1      0      1      Yousef,Olivia          
#4   126 Kyle    Alex     Janice    0      0      0      ""                     
#5   127 Marisa  Marcus   Josephine 1      1      1      Marisa,Marcus,Josephine

详情:

pivot_longer 将我们的数据转换为更自然的格式,其中每一行代表对变量 agent 和 flag 的一次观察,而不是多个:


pivot_longer(data1, 
             cols = -ID, 
             names_to = c(".value", "group"),
             names_sep = "_")

## A tibble: 15 x 4
#      ID group agent     Flag 
#   <int> <chr> <chr>     <chr>
# 1   123 1     James     1    
# 2   123 2     Sophie    0    
# 3   123 3     Justine   1    
# 4   124 1     Lucas     0    
# 5   124 2     Danielle  1    
# 6   124 3     Adrienne  0 
# ...

对于每个 ID,我们可以将标志值为 1 的代理粘贴在一起。现在我们的变量包含在单个列中,这很容易。

最后,我们使用pivot_wider 恢复为wide 格式。我们还将之前分组的数据取消分组,并将列重新排序为所需的格式。

【讨论】:

  • 嗨,克里斯,非常感谢您的回复。我想我没有必要的 tidyr 版本,因为我收到了找不到函数轴更长的错误。我有 agent_1: agent_10,这个解决方案是否适用于 3 个以上的变量?
  • @DanielleTravassos 是的,只需使用install.packages('tidyr') 安装最新的tidyr 版本。只要您唯一的列是agent_iFlag_i,这将起作用。如果您还有其他列,则必须更改 pivot_longer 中的 cols 规范
  • 谢谢!由于我无法更改正在使用的 R 版本,您对我可以使用的其他功能有什么建议吗?
  • @DanielleTravassos 你用的是什么 R 版本?
  • 我在 3.5.1。谢谢
【解决方案2】:

在 BaseR 或 tidyverse 中有几种不同的方法可以做到这一点,或者两者的结合,如果你坚持使用 tidyverse,那么考虑一下:

我已使用 mtcars 作为您的数据框!

#load dplyr or tidyverse
library(tidyverse)

# create data as mtcars
df <- mtcars

# create two new columns flag and agent as rownumbers
df <- df %>% 
  mutate(flag = paste0("flag", row_number())) %>% 
  mutate(agent = paste0("agent", row_number()))

# using case when in mutate statement
df2 <- df %>%  
  mutate(new_column = ifelse(flag == "flag1", yes = paste0(agent, " this is a new variable"), no = flag))

print(df2)

如果您有一个案例,则 ifelse 语句可能更合适 - 但如果您有多个案例,请改用 case_when

【讨论】:

  • 您好,感谢您的帮助。它确实有效,但只有一次,因为它没有循环。
  • 是的 - 这是不使用 for 循环的一种方便方法 - 如果需要,您可以使用循环,但您的问题更多是数据争论练习,所以我认为使用它会更容易tidyverse/dplyr 代替。如果您对答案感到满意,请点击绿色勾号接受它,谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-06-22
  • 2014-05-21
  • 1970-01-01
  • 2022-06-23
  • 2018-06-14
  • 2015-05-04
  • 2019-04-20
相关资源
最近更新 更多