基于条件的乘列和使用R放置逗号分隔符

9rbhqvlz  于 2022-12-27  发布在  其他
关注(0)|答案(2)|浏览(189)

我有下面的 Dataframe ,基于一个条件--文本中出现百万或千--我需要将数字列乘以百万或千,然后放置一个千分隔符:

df <- data.frame(col1=c('', 'assets', 'loss', 'liability'),
                 col2=c(NA, 5000, -1400, 300),
                 col3=c(NA, 4500, -1100, 500))

df

col1        col2    col3
<chr>       <dbl>   <dbl>
             NA      NA
assets      5000    4500
loss       -1400   -1100
liability   300      500
                                                                  ​               ​        ​

我正在尝试下面的脚本,以查看出现了哪种条件-- million还是thousand --,乘以该条件,然后放置一个千分隔符:

multiply_columns <- function(df){

  text <- "in millions, except share and per share data"

  # Iterate over the columns
  for (idx in 2:length(names(df))) {
      
      # Check if text contains million
      if (grepl(text, "in millions", fixed = TRUE)) {
        
        # If yes, multiply column values with million else thousand
        df[, idx] <- format(df[, idx]*1000000, big.mark=",", scientific=FALSE)
      
      } else 
        df[, idx] <- format(df[, idx]*1000, big.mark=",", scientific=FALSE)
}  
  return(df)
}

看起来这个函数没有正确地相乘。它是乘以1000,而文本包含了数百万。

multiply_columns(df)

col1             col2          col3
<chr>           <chr>          <chr>
                 NA            NA
assets        5,000,000     4,500,000
loss         -1,400,000    -1,100,000
liability     300,000       500,000

所需输出

col1             col2           col3
<chr>            <dbl>          <dbl>
                  NA             NA
assets        5,000,000,000   4,500,000,000
loss         -1,400,000,000   -1,100,000,000
liability     300,000,000     500,000,000

如有任何建议,将不胜感激。谢谢!

k97glaaz

k97glaaz1#

我更熟悉tidyverse函数,但下面是我将如何构造函数:

library(tidyverse)

conv_th_or_mm <- function(df, text){

  if(str_detect(text, regex("million", ignore_case=T))){

    df <- df %>%
      mutate(
        across(
          .cols = where(is.numeric),
          .fns = ~.x*1000000
        )
      )

  } else {

    df <- df %>%
      mutate(
        across(
          .cols = where(is.numeric),
          .fns = ~.x*1000
        )
      )

  }

  df <- df %>%
    mutate(
      across(
        .cols = where(is.numeric),
        .fns = ~formatC(.x, big.mark=",", digits=0, format="f")
      )
    )

  return(df)
}

有几点:

  • 我添加了text作为函数的参数,我认为您可能希望根据 Dataframe 传入该参数。
  • 我以前只使用过formatC(),所以我使用了等效的参数来匹配format()函数。
  • 我给你的函数取了一个稍微不同的名字,这也许现在不重要了,但是如果你一年后再看它的话,你会发现你写了24个其他的函数。
  • 如果您的用例需要它,您可以更具体地使用. cols,但我假设所有的数值都需要转换。

编辑并补充一点,R在查找您调用的变量时非常灵活,如果您在函数中调用它,尽管没有将其作为参数传入,R也可能在全局环境中查找text(对于其他语言来说,这是一种奇怪的行为)但是,如果函数外部的数据是my_df,而要计算的文本是my_text,你可以这样使用我的函数

my_df <- conv_th_or_mm(df = my_df, text = my_text)
bxfogqkk

bxfogqkk2#

我们可以将thousandmillion取出,替换为1e31e6进行相乘,假设text可以输入到函数中

library(dplyr)
multiply_columns <- function(df, text){

 val_to_mult <- as.numeric(stringr::str_replace_all(stringr::str_extract(text, 
      "million|thousand|billion"),  setNames(c("1e3", "1e6", "1e9"), 
            c("thousand", "million", "billion"))))
 df %>%
    mutate(across(where(is.numeric), ~ scales::comma(.x * val_to_mult)))
    }
  • 测试
> text <- "in millions, except share and per share data"
> multiply_columns(df, text)
     col1           col2           col3
1                     <NA>           <NA>
2    assets  5,000,000,000  4,500,000,000
3      loss -1,400,000,000 -1,100,000,000
4 liability    300,000,000    500,000,000

> multiply_columns(df, "in thousands")
    col1       col2       col3
1                 <NA>       <NA>
2    assets  5,000,000  4,500,000
3      loss -1,400,000 -1,100,000
4 liability    300,000    500,000

> multiply_columns(df, "in billion")
    col1               col2               col3
1                         <NA>               <NA>
2    assets  5,000,000,000,000  4,500,000,000,000
3      loss -1,400,000,000,000 -1,100,000,000,000
4 liability    300,000,000,000    500,000,000,000

相关问题