Как бы вы написали функцию-оболочку или класс для форматирования чисел в процентах, валюте и т.д. В R?

В предыдущем вопросе я спросил, существует ли в базе R удобная оболочка для форматирования чисел в процентах.

Это вызвало три ответа:

  • Возможно, нет.
  • Такая оболочка будет слишком узкой, чтобы быть полезной. Лучше, чтобы useRs узнал, как использовать существующие инструменты, такие как sprintf, который может форматировать номера очень гибким способом.
  • Такая оболочка является проблематичной, так или иначе, поскольку вы теряете возможность выполнять вычисления на объекте.

Тем не менее, на мой взгляд, функция sprintf просто немного запутана для начинающего R, чтобы учиться (за исключением случаев, когда они происходят из фона C). Возможно, лучшим решением является изменение format или prettyNum, чтобы иметь опции для добавления префиксов и суффиксов, поэтому вы можете легко создавать проценты, валюты, градусы и т.д.


Вопрос:

Как бы вы разработали функцию, класс или набор функций для элегантного решения чисел форматирования в процентах, валютах, градусах и т.д.

Ответ 1

Я бы, наверное, делал все очень просто. format() обычно полезен для большинства основных потребностей форматирования. Я бы расширил это с помощью простой оболочки, которая допускала бы строки prefix и suffix. Вот простая версия:

formatVal <- function(x, prefix = "", suffix = "", sep = "", collapse = NULL,
                      ...) {
    x <- format(x, ...)
    x <- paste(prefix, x, suffix, sep = sep, collapse = collapse)
    x
}

Если бы я делал это по-настоящему, я бы, вероятно, не имел аргумент collapse в определении formatVal(), а вместо этого обрабатывал его из ..., но для иллюстрации я сохранил эту функцию просто.

Использование:

set.seed(1)
m <- runif(5)

несколько простых примеров использования

> formatVal(m*100, suffix = "%")
[1] "26.55087%" "37.21239%" "57.28534%" "90.82078%" "20.16819%"
> formatVal(m*100, suffix = "%", digits = 2)
[1] "27%" "37%" "57%" "91%" "20%"
> formatVal(m*100, suffix = "%", digits = 2, nsmall = 2)
[1] "26.55%" "37.21%" "57.29%" "90.82%" "20.17%"
> formatVal(m, prefix = "£")
[1] "£0.2655087" "£0.3721239" "£0.5728534" "£0.9082078" "£0.2016819"
> formatVal(m, prefix = "£", digits = 1)
[1] "£0.3" "£0.4" "£0.6" "£0.9" "£0.2"
> formatVal(m, prefix = "£", digits = 1, nsmall = 2)
[1] "£0.27" "£0.37" "£0.57" "£0.91" "£0.20"

Ответ 2

print.formatted <- function(x)
{
   print(paste(attr(x,"prefix"), sprintf(x*attr(x,"scaleFactor"),fmt=paste("%.",attr(x,"precision"),"f",sep="")), attr(x,"suffix"), sep=""))
}

as.percent <- function(x,precision=3)
{
  class(x) <- c(class(x),"formatted")
  attr(x,"scaleFactor")<-100
  attr(x,"prefix")<-""
  attr(x,"suffix")<-"%"
  attr(x,"precision")<-precision
  return(x)
}

as.currency <- function(x,prefix="£")
{
  class(x) <- c(class(x),"formatted")
  attr(x,"scaleFactor")<-1
  attr(x,"prefix")<-prefix
  attr(x,"suffix")<-""
  attr(x,"precision")<-2
  return(x)
}

as.percent(runif(3))
[1] "21.585%" "12.396%" "37.744%"

x <- as.currency(rnorm(3,500,100))
x
[1] "£381.93" "£339.49" "£521.74"
2*x
[1] "£763.86"  "£678.98"  "£1043.48"

Ответ 3

Я думаю, что это можно сделать с помощью атрибутов, например. пусть v <- 3.4. Если это фунт стерлингов, мы могли бы использовать что-то вроде:

attributes(v)<-list(style = "descriptor", type = "currency", category = "pound")

Если это процент:

attributes(v)<-list(style = "descriptor", type = "proportion", category = "percentage")

Тогда потребуется специальный метод печати. Можно также включить способ перевода, например. конвертировать из GBP в USD (фунты в доллары), сантиметры в дюймы и т.д.

descriptor - это, по существу, мой взгляд на зарезервированный вид флага для указания специальной обработки для данного номера. Впоследствии это можно было бы расширить до текстовых строк, таких как адреса и имена. Для других номеров, таких как номера телефонов, могут быть специальные разложения в код страны, внутригородские/региональные коды, вплоть до расширений.

Такой пакет может быть сродни ggplot для типов данных - специальные методы для хранения, преобразования и печати вещей внутри типов?

Такая система может гарантировать правильность размеров при умножении значений. Это имеет реальную полезность во многих приложениях.

Насколько мне известно, единственная распространенная обработка единиц в R - это байты (байты, КБ, МБ и т.д.) и время (часы, секунды и т.д.). Тем не менее, обработка, хотя и простая, не очевидна - мне все еще нужно сказать print единицам, которые вы используете. Например, если я хочу напечатать размер объекта в КБ, я не могу просто вычислить object.size(v)/1024 - вывод будет отображаться в долях байта, а не в КБ; Я должен использовать print(object.size(v), units = "K").

Ответ 4

ggplot2 имеет кучу функций для форматирования общих конкретных случаев. Они были бы идеальными, но для двух вещей: они не достаточно общие, и вам не нужно загружать ggplot2 (со всеми его зависимостями), чтобы получить такие функции. Вы можете попытаться связаться с Хэдли, чтобы получить подписи, чтобы передать больше вещей для форматирования и переместить их в пакет более низкого уровня (plyr возможно, или их собственный пакет, ggtools?).