R语言 我的向量到列的代码优化

hm2xizp9  于 2023-05-26  发布在  其他
关注(0)|答案(4)|浏览(191)

有没有更好的方法在R中优化这段代码

df = data.frame("Population" = c("4.88M", "3.12M", "819k",  "4660",  "46.7k", "4.86M", "856k"))
int_list <- numeric(nrow(df))
for (y in 1:nrow(df)) {
  i <- df$Population[y]
  if (str_detect(i, "k")){
    no_k <- gsub("k", "", i)
    x <- as.numeric(no_k)
    fix_X <- x * 1000
  } else if (str_detect(i, "M")) {
    no_M <- gsub("M", "", i)
    x <- as.numeric(no_M)
    fix_X <- x * 1000000
  } else {
    fix_X <- as.numeric(i)
  }
  int_list[y] = fix_X
}
df$pop_fix <- int_list

编辑:添加DF示例
我得到了我需要的结果,只是想知道我是否可以做得更好,我试过ifelse语句,但它们总是导致错误,我也试过把它放在列中,但它会把过去的值覆盖到最后一个

bz4sfanl

bz4sfanl1#

这里有一个简化的尝试。去掉除了k/M后缀之外的所有内容,然后去掉k/M,并使用后缀的一些索引来确定乘数:

sel <- gsub("[^Mk]", "", df$Population)
val <- as.numeric(gsub("[Mk]",  "", df$Population))
df$pop_fix2 <- ifelse(sel == "", val, val * c("M"=1000000, "k"=1000)[sel])

给出请求的结果:

#  Population pop_fix pop_fix2
#1      4.88M 4880000  4880000
#2      3.12M 3120000  3120000
#3       819k  819000   819000
#4       4660    4660     4660
#5      46.7k   46700    46700
#6      4.86M 4860000  4860000
#7       856k  856000   856000
umuewwlo

umuewwlo2#

我们可以使用tidyverse首先separate取幂器的数值。然后将符号指数转换为一个合适的以10为底的数字,最后通过简单的乘法来调整种群。

library(dplyr)
library(tidyr)

df |>
    separate_wider_regex(col = Population,
                         patterns = c(population = "[0-9.]+",
                                      magnitude = "[A-Za-z]"),
                         too_few = "align_start"
    ) |> type_convert() |>
    mutate(magnitude = case_match(magnitude,
                                  "M" ~ 6,
                                  "k" ~ 3,
                                  .default = 1
                                  )
           ) |> 
    mutate(population = population * (10^ magnitude),
           .keep = "none")

# A tibble: 7 × 1
  population
       <dbl>
1    4880000
2    3120000
3     819000
4      46600
5      46700
6    4860000
7     856000
ua4mk5z4

ua4mk5z43#

df[c("pop", "pop_scale")] <- data.table::tstrsplit(df$Population, "(?=(M|k))", perl = TRUE)
df$pop_scale              <- replace(df$pop_scale, is.na(df$pop_scale), "as_is")
df$pop                    <- as.numeric(df$pop)
df$pop_fix                <- df$pop * c(M=1e6, k=1e3, as_is=1)[df$pop_scale]

#   Population     pop pop_scale pop_fix
# 1      4.88M    4.88         M 4880000
# 2      3.12M    3.12         M 3120000
# 3       819k  819.00         k  819000
# 4       4660 4660.00     as_is    4660
# 5      46.7k   46.70         k   46700
# 6      4.86M    4.86         M 4860000
# 7       856k  856.00         k  856000
2nbm6dog

2nbm6dog4#

**1)**这里有一个一行代码。未使用任何包。

transform(df, pop_fix = as.numeric(sub("k", "e3", sub("M", "e6", Population))))
##   Population pop_fix
## 1      4.88M 4880000
## 2      3.12M 3120000
## 3       819k  819000
## 4       4660    4660
## 5      46.7k   46700
## 6      4.86M 4860000
## 7       856k  856000

**2)**或使用Reduce

L <- list(k = "e3", M = "e6")
transform(df, pop_fix = as.numeric(Reduce(\(x, nm) sub(nm, L[[nm]], x), 
  init = Population, names(L))))

**3)**这也可以工作,并且在概念上同时进行两个替换:

library(gsubfn)

transform(df, pop_fix = as.numeric(gsubfn(".", list(M="e6",k="e3"), Population)))

相关问题