从十亿转换为百万,反之亦然
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
请注意bn
和Mn
是向量的一部分。
【问题讨论】:
所以你想让他们全部数百万或数十亿? 我想把所有东西都换成十亿 相关,一些不错的自定义函数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
【讨论】:
以上是关于从十亿转换为百万,反之亦然的主要内容,如果未能解决你的问题,请参考以下文章