从十亿转换为百万,反之亦然

Posted

技术标签:

【中文标题】从十亿转换为百万,反之亦然【英文标题】:Convert from billion to million and vice versa 【发布时间】:2016-06-24 12:13:54 【问题描述】:

假设我有以下名为DF 的数据框。我想将Revenue 列中的所有值转换为相同的单位。

Brands   Revenue
A        50.1 bn
B        41.2 bn
C        32.5 Mn
D        15.1 bn

请注意bnMn 是向量的一部分。

【问题讨论】:

所以你想让他们全部数百万或数十亿? 我想把所有东西都换成十亿 相关,一些不错的自定义函数in this post. 【参考方案1】:

一个想法,

new <- ifelse(gsub('.*\\s+', '', DF$Revenue) == 'bn',
              as.numeric(gsub('[A-Za-z]', '', DF$Revenue))*1000, DF$Revenue)

new[!grepl('Mn', new)] <- paste(new[!grepl('Mn', new)], 'Mn', sep = ' ')
DF$Revenue <- new

DF
#  Brands  Revenue
#1      A 50100 Mn
#2      B 41200 Mn
#3      C  32.5 Mn
#4      D 15100 Mn

然后做相反的事情,

new <- ifelse(gsub('.*\\s+', '', DF$Revenue) == 'Mn',
               as.numeric(gsub('[A-Za-z]', '', DF$Revenue))/1000, DF$Revenue)

 new[!grepl('bn', new)] <- paste(new[!grepl('bn', new)], 'bn', sep = ' ')
 DF$Revenue <- new
 DF
#  Brands   Revenue
#1      A   50.1 bn
#2      B   41.2 bn
#3      C 0.0325 bn
#4      D   15.1 bn

【讨论】:

【参考方案2】:

另一种方法:使用split将货币值与文本分开:

# split value and "level" in a list
temp <- split(df$Revenue, split=" ")
# add separately to data.frame
df$Revenue <- sapply(temp, function(i) as.numeric(i[[1]]))
df$level <- sapply(temp, function(i) "[", 2)

df
  Brands Revenue level
1      A 50100.0    bn
2      B 41200.0    bn
3      C    32.5    bn
4      D 15100.0    bn

现在,在具有“bn”的级别上转换为百万子集:

df$Revenue[df$level == "bn"] <- df$Revenue[df$level == "bn"] * 1000
df$level <- "Mn"

这会导致

df
  Brands Revenue level
1      A  0.0501    Mn
2      B  0.0412    Mn
3      C 32.5000    Mn
4      D  0.0151    Mn

改为转换为数十亿(类似的过程)

df$Revenue[df$level == "Mn"] <- df$Revenue[df$level == "Mn"] / 1000
df$level <- "bn"

这会导致

df
  Brands Revenue level
1      A  0.0501    bn
2      B  0.0412    bn
3      C 32.5000    bn
4      D  0.0151    bn

【讨论】:

【参考方案3】:

与以前的解决方案相比,可能会简化解析过程。 我正在使用很棒的库stringr:

library(stringr)

dd$units <- word(dd$Revenue, 2, sep = " ")
dd$amounts <- word(dd$Revenue, 1, sep = " ")


# The following lines create an extra column in the dataframe,
# You can overwrite the original column if you so wish.

# Convert to billions
dd$convert_to_bn <- paste(as.numeric(dd$amounts) * ifelse(dd$units == "bn", 1 , 0.001), "bn")

# Convert to millions
dd$convert_to_mn <- paste(as.numeric(dd$amounts) * ifelse(dd$units == "Mn", 1 , 1000), "Mn")

【讨论】:

【参考方案4】:

这是一种用适当的因素替换“单位”并评估结果计算的解决方案。

第一步是将“bn”和“Mn”替换为一个因子:

conversion <- c(Mn = 1/1000, bn = 1)
for (unit in names(conversion)) 
  df$Revenue <- gsub(unit, paste0("*", conversion[unit]), df$Revenue)

df
##   CBrands             Revenue
## 1       A             50.1 *1
## 2       B             41.2 *1
## 3       C         32.5 *0.001
## 4       D             15.1 *1

然后再次计算 Revenue 和 "bn" 中的表达式:

df$Revenue <- sapply(df$Revenue, function(x) eval(parse(text = x)))
df$Revenue <- paste(df$Revenue, "bn")
df
##   CBrands   Revenue
## 1       A   50.1 bn
## 2       B   41.2 bn
## 3       C 0.0325 bn
## 4       D   15.1 bn

【讨论】:

虽然这可行,但值得注意的是,随着行数的增加,基于apply() 的解决方案不会像矢量化解决方案那样缩放,尤其是当循环的每次迭代都调用eval(parse(...)) 时.【参考方案5】:

我们也可以使用gsubfn 来做到这一点。将 'bn'、'Mn' 替换为 * 1* 1/1000,评估字符串并粘贴为 'bn'。

library(gsubfn)
sprintf("%.2f bn", sapply(gsubfn("([[:alpha:]]+)", list(Mn = "* 1/1000", 
        bn = "* 1"), df1$Revenue), function(x) eval(parse(text=x))))
#[1] "50.10 bn" "41.20 bn" "0.03 bn"  "15.10 bn"

【讨论】:

【参考方案6】:

您应该考虑是否真的希望将收入作为文本存储在数据中。这将使对收入进行任何类型的计算变得更加困难。您可能会发现将收入存储为浮点数并编写自定义格式以使用后缀显示它会更好。计量单位可以是个、十亿或其他任何单位。

根据您的决定,这里有两种使用流行的“tidyverse”包的方法。在这两种方法中,使用 tidyr 的 separate(..., sep='\\s',convert=TRUE) 将您的收入文本拆分为数字和单位。

将收入存储为文本(不是最佳做法)

library(tidyr)
library(dplyr)
DF %>% 
  separate(Revenue, into=c('Rev.Amt','Rev.Denom'), sep='\\s', convert=TRUE) %>%
  mutate( Rev.Amt = Rev.Amt/ifelse(Rev.Denom=='Mn',1000,1), # other conversions as needed
          Rev.Denom = 'bn' ) %>%
  unite(Revenue, Rev.Amt, Rev.Denom, sep=' ')
# Brands   Revenue
# 1      A   50.1 bn
# 2      B   41.2 bn
# 3      C 0.0325 bn
# 4      D   15.1 bn

将收入存储为数字(更好的做法)

在这里,我们将收入存储为没有倍数的单位,但您也可以将其存储为十亿,避免显示时的除法步骤。

DF %<>% 
  separate(Revenue, into=c('Rev.Amt','Rev.Denom'), sep='\\s', convert=TRUE) %>%
  mutate( Rev.Amt = Rev.Amt*ifelse(Rev.Denom=='Mn', 1e6, 1e9)) %>% # other conv as needed
  select(-Rev.Denom)

# To display numeric revenue in billions
showInBn <- function(x) paste(x/1e9,'bn')
DF %>% mutate(Rev.Expr = showInBn(Rev.Amt)) %>% select(-Rev.Amt)
#   Brands  Rev.Expr
# 1      A   50.1 bn
# 2      B   41.2 bn
# 3      C 0.0325 bn
# 4      D   15.1 bn

【讨论】:

以上是关于从十亿转换为百万,反之亦然的主要内容,如果未能解决你的问题,请参考以下文章

用百万 (M) 和十亿 (B) 后缀格式化数字

如何在 PHP 中为数字(千、十万、百万、十亿)添加逗号分隔符

谷歌表格将数字格式化为十亿/百万/数千,巧妙地[重复]

具有数千、数百万和数十亿的问题排序数字(货币)

字符串格式数字千位123K、百万位123M、十亿位123B

Excel图表不保持格式