假设我有以下名为DF
的数据框。我想将Revenue
列中的所有值转换为相同的单位。
Brands Revenue
A 50.1 bn
B 41.2 bn
C 32.5 Mn
D 15.1 bn
请注意,bn
和Mn
是向量的一部分。
答案 0 :(得分:8)
一个想法,
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
答案 1 :(得分:4)
另一种方法:使用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
现在,使用&#34; bn&#34;:
转换为数百万个子集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
答案 2 :(得分:4)
与先前的解决方案相比,可能简化解析过程。 我正在使用令人敬畏的库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")
答案 3 :(得分:3)
这是一个替代&#34;单位&#34;的解决方案。通过适当的因素并评估最终的计算结果。
第一步是替换&#34; bn&#34;和&#34; Mn&#34;由一个因素:
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
和&#34; bn&#34;中的表达式再次:
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
答案 4 :(得分:1)
我们也可以使用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"
答案 5 :(得分:0)
您应该考虑是否确实希望将收入存储为数据中的文本。这将使得对收入进行任何类型的计算变得更加困难。您可能会发现将收入存储为浮点数并编写自定义格式以使用后缀显示它更好。衡量单位可以是1,数十亿或其他任何东西。
根据您的决定,以下是使用流行的“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