Преобразование сокращений единиц в числа - PullRequest
4 голосов
/ 16 мая 2019

У меня есть набор данных, который сокращает числовые значения в столбце. Например, 12 миллионов означает 12 миллионов, 1,2 тысячи означает 1200. М и к - единственные сокращения. Как я могу написать код, который позволяет R сортировать эти значения по возрастанию?

Хотя я и использовал gsub для преобразования M в 000 000 и т. Д., Но это не учитывает десятичные дроби (тогда 1,5M будет 1,5000000).

Ответы [ 4 ]

5 голосов
/ 16 мая 2019
  • Таким образом, вы хотите перевести аббревиатуры единиц СИ ('K', 'M', ...) в показатели степени, и, таким образом, в числовые степени десяти. Учитывая, что все единицы являются однобуквенными, а показатели степени - равномерно разнесенными степенями 10 ** 3, вот рабочий код, который обрабатывает 'Kilo' ... 'Yotta', и любые будущие показатели:
    > 10 ** (3*as.integer(regexpr('T', 'KMGTPEY')))
    [1] 1e+12

Затем просто умножьте эту степень десяти на десятичное значение, которое у вас есть.

  • Кроме того, вы, вероятно, захотите обнаружить и обработать случай «без совпадения» для неизвестных буквенных префиксов, в противном случае вы получите бессмысленный -1*3
    > unit_to_power <- function(u) {
        exp_ <- 10**(as.integer(regexpr(u, 'KMGTPEY')) *3)
        return (if(exp_>=0) exp_ else 1)
    }
  • Теперь, если вы хотите, чтобы регистр без учета регистра соответствовал и «k», и «K» (как часто пишут компьютерные люди, даже если это технически злоупотребление СИ), вам нужно -case, например, с помощью лестничного выражения / выражения if-else (единицы измерения SI, как правило, чувствительны к регистру, «M» означает «Мега», но «m» строго означает «милли», даже если пользователи дисковода говорят иначе; верхний регистр обычно для положительных показателей). Так что для нескольких префиксов код @ DanielV для конкретного случая лучше.

  • Если вы также хотите использовать отрицательные префиксы SI, используйте as.integer(regexpr(u, 'zafpnum@KMGTPEY')-8), где @ - просто какой-то однозначный символ, чтобы сохранить одинаковый интервал, он не должен совпадать. Опять же, если вам нужно обработать не-10-кратные единицы **, такие как 'deci', 'centi', потребуется специальный регистр или общий подход на основе dict, который использует WeNYoBen.

  • base::regexpr не векторизовано, его производительность на больших входах плохая, поэтому, если вы хотите векторизовать и получить более высокую производительность, используйте stringr::str_locate.

3 голосов
/ 16 мая 2019

Дайте этому шанс:

Text_Num <- function(x){
    if (grepl("M", x, ignore.case = TRUE)) {
        as.numeric(gsub("M", "", x, ignore.case = TRUE)) * 1e6
    } else if (grepl("k", x, ignore.case = TRUE)) {
        as.numeric(gsub("k", "", x, ignore.case = TRUE)) * 1e3
    } else {
        as.numeric(x)
    }
}
1 голос
/ 16 мая 2019

В вашем случае вы можете использовать gsubfn

a=c('12M','1.2k')
dict<-list("k" = "e3", "M" = "e6")
as.numeric(gsubfn::gsubfn(paste(names(dict),collapse="|"),dict,a))
[1] 1.2e+07 1.2e+03
0 голосов
/ 16 мая 2019

Я рад с вами познакомиться.

Я написал другой ответ

Определить функцию

res = function (x) {
  result = as.numeric(x)
  if(is.na(result)){
  text = gsub("k", "*1e3", x, ignore.case = T)
  text = gsub("m", "*1e6", text, ignore.case = T)
  result = eval(parse(text = text))
  } 
  return(result)
}

Результат

> res("5M")
[1] 5e+06
> res("4K")
[1] 4000
> res("100")
[1] 100
> res("4k")
[1] 4000
> res("1e3")
[1] 1000
...