【问题标题】:Nested loop doesn't bring the desired result嵌套循环不会带来预期的结果
【发布时间】:2020-06-15 01:27:41
【问题描述】:

我对 r 还很陌生,所以这可能是一个愚蠢的疑问。

我有一个数据框,我想在其中循环浏览特定列中的行并检查其中的名称是否在另一个变量中。虽然,每一行中的值可能有多个用分号分隔的名称。我需要检查每一个。我尝试了一个嵌套循环,但我得到了重复值的列表。我的代码描述如下:

# Column in df I want to modify:
company.tickers  
----------
CARD3  
CSAN3  
CVCB3  
ELET3;ELET5;ELET6  
ENBR3  
FESA3;FESA4  
OIBR3;OIBR4  
PETR3;PETR4  
PTBL3  
TUPY3  
VLID3  

# stock names I would like to keep
stocks <- c("CARD3", "TUPY3", "OIBR3", "FESA4", "PTBL3", "VLID3","CNTO3","CSAN3","ELET3","PETR4","ENBR3")

result=list()

# Cycle through rows
for (i in 1:length(df.statements$company.tickers)){

  print(df.statements$company.tickers[i])
  stock.tickers <- strsplit(row,";")

  # Cycle through names in a cell
  for (j in 1:length(stock.tickers)) {

    if (stock.tickers[j] %in% stocks){

      print(stock.tickers[j])

      result <- c( result, stock.tickers[j])

    }

  }

}

# My expected result is the following column:
company.tickers 
----------
CARD3  
CSAN3  
CVCB3  
ELET3
ENBR3  
FESA4  
OIBR3
PETR4  
PTBL3  
TUPY3  
VLID3 

【问题讨论】:

    标签: r loops for-loop foreach


    【解决方案1】:

    这里尝试使用tidyr::separate 将代码列临时拆分为单独的列。加长/整理数据,然后过滤得到你想要的。

    我会感谢帮助改进这项技术的 cmets。

    suppressPackageStartupMessages(library(dplyr))
    suppressPackageStartupMessages(library(tidyr))
    suppressPackageStartupMessages(library(purrr))
    
    company.tickers = c(
      "CARD3",
      "CSAN3",
      "CVCB3",
      "ELET3;ELET5;ELET6",
      "ENBR3",
      "FESA3;FESA4",
      "OIBR3;OIBR4",
      "PETR3;PETR4",
      "PTBL3",
      "TUPY3",
      "VLID3")
    
    random.data <- runif(length(company.tickers))
    stocks <- c("CARD3", "TUPY3", "OIBR3", "FESA4", "PTBL3", "VLID3", "CNTO3", "CSAN3", "ELET3", "PETR4", "ENBR3")
    
    # construct a data frame
    df <- dplyr::tibble(company.tickers, random.data)
    
    # work out how many columns `separate` will need, and create a vector of unusual column names
    # it feels weird that we need to do this
    # but without this I always get an error from `separate` in the next step
    
    new_cols <- paste0("zqzcol", 1:max(map_int(strsplit(df$company.tickers, ";"), length)))
    
    # temporarily create new columns using `separate`
    # then use `pivot_longer` to reabsorb these into long, tidy data
    # then filter this by what is in `stocks`
    # then tidy up using `select` (optional)
    
    df %>% 
      tidyr::separate(col = company.tickers, sep = ";", into = new_cols) %>% 
      pivot_longer(cols = starts_with("zqzcol"), values_to = "company.tickers", values_drop_na = TRUE) %>% 
      filter(company.tickers %in% stocks) %>% 
      select(company.tickers, everything(), -name)
    #> Warning: Expected 3 pieces. Missing pieces filled with `NA` in 10 rows [1, 2, 3,
    #> 5, 6, 7, 8, 9, 10, 11].
    #> # A tibble: 10 x 2
    #>    company.tickers random.data
    #>    <chr>                 <dbl>
    #>  1 CARD3                0.568 
    #>  2 CSAN3                0.0370
    #>  3 ELET3                0.119 
    #>  4 ENBR3                0.276 
    #>  5 FESA4                0.196 
    #>  6 OIBR3                0.301 
    #>  7 PETR4                0.504 
    #>  8 PTBL3                0.712 
    #>  9 TUPY3                0.790 
    #> 10 VLID3                0.956
    

    reprex package (v0.3.0) 于 2020-03-05 创建

    【讨论】:

    • 谢谢你的答案!我仍然得到与预期不同的结果:小标题:13 x 2,不应该存在的 PETR3 和 ELET6。
    • 好吧,我已经提供了一个代表,所以如果你的结果不同,你必须输入与我提供的不同的东西(或者有一些明显不同的包版本!)尝试提供一个代表(搜索这个如果你不知道怎么做),看看会发生什么。
    • 您有 16 只股票在股票代码栏中提及,11 只股票上市,其中 1 只(“CNTO3”)不匹配。所以我原以为你会得到一个 10 行的小标题作为所需的输出。
    【解决方案2】:

    tidyverse 替代 Wimpel 非常聪明的答案:

    suppressPackageStartupMessages(library(dplyr))
    
    company.tickers = c(
    "CARD3",
    "CSAN3",
    "CVCB3",
    "ELET3;ELET5;ELET6",
    "ENBR3",
    "FESA3;FESA4",
    "OIBR3;OIBR4",
    "PETR3;PETR4",
    "PTBL3",
    "TUPY3",
    "VLID3")
    
    stocks <- c("CARD3", "TUPY3", "OIBR3", "FESA4", "PTBL3", "VLID3", "CNTO3", "CSAN3", "ELET3", "PETR4", "ENBR3")
    
    df <- dplyr::tibble(company.tickers)
    
    filter_df <- function(x, df, col) {
      df %>% 
        dplyr::filter(stringr::str_detect(.data[[col]], x))
    }
    
    purrr::map_dfr(stocks, ~ filter_df(., df = df, col = "company.tickers")) %>% 
      dplyr::distinct()
    #> # A tibble: 10 x 1
    #>    company.tickers  
    #>    <chr>            
    #>  1 CARD3            
    #>  2 TUPY3            
    #>  3 OIBR3;OIBR4      
    #>  4 FESA3;FESA4      
    #>  5 PTBL3            
    #>  6 VLID3            
    #>  7 CSAN3            
    #>  8 ELET3;ELET5;ELET6
    #>  9 PETR3;PETR4      
    #> 10 ENBR3
    

    reprex package (v0.3.0) 于 2020 年 3 月 3 日创建

    【讨论】:

    • 可能我不太清楚或者没看懂你们写的代码。结果应该只有库存中的项目。因此,“OIBR4”、“FESA3”、“PETR3”、“ELET5”和“ELET6”应从该列中删除。我的主要问题是处理具有多个值的行(用分号分隔)。
    • 哦,好吧-我确实想知道,但是您的问题不够具体。模拟一个您想要的结果的示例通常是一个好主意。我开始写一个答案,使用tidyr::separate 用分号分隔字符串,但随后改变了方向。我会再尝试。也许您可以编辑您的问题,以便完全清楚您需要什么结果。
    • 此答案使用来自purrrmap 函数来生成您在原始问题中询问的循环过程。我的另一个答案没有以同样的方式进行显式循环。
    【解决方案3】:

    大概是这样的吧?

    #build regex
    stocks.regex <- paste0( stocks, collapse = "|")
    #subset using grepl ans the new regex
    subset( df, grepl( stocks.regex, df$company.tickers ) )
    

    样本数据

    library(data.table)
    df <- setDF(fread("company.tickers  
    CARD3  
    CSAN3  
    CVCB3  
    ELET3;ELET5;ELET6  
    ENBR3  
    FESA3;FESA4  
    OIBR3;OIBR4  
    PETR3;PETR4  
    PTBL3  
    TUPY3  
    VLID3", sep = ","))
    
    stocks <- c("CARD3", "TUPY3", "OIBR3", "FESA4", "PTBL3", "VLID3","CNTO3","CSAN3","ELET3","PETR4","ENBR3")
    

    【讨论】:

      猜你喜欢
      • 2021-11-03
      • 1970-01-01
      • 2013-06-05
      • 2013-04-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多