Как добавить ведущие нули?

222

У меня есть набор данных, который выглядит примерно так:

anim <- c(25499,25500,25501,25502,25503,25504)
sex  <- c(1,2,2,1,2,1)
wt   <- c(0.8,1.2,1.0,2.0,1.8,1.4)
data <- data.frame(anim,sex,wt)

data
   anim sex  wt anim2
1 25499   1 0.8     2
2 25500   2 1.2     2
3 25501   2 1.0     2
4 25502   1 2.0     2
5 25503   2 1.8     2
6 25504   1 1.4     2

Я хочу, чтобы перед каждым идентификатором животного добавлялся ноль:

data
   anim sex  wt anim2
1 025499   1 0.8     2
2 025500   2 1.2     2
3 025501   2 1.0     2
4 025502   1 2.0     2
5 025503   2 1.8     2
6 025504   1 1.4     2

И ради интереса, что, если мне нужно добавить два или три нуля до идентификатора животного?

  • 5
    Предположим, что вы хотите добавить n нулей перед идентификаторами животных, вам просто нужно сделать data$anim = paste(rep(0, n), data$anim, sep = "")
  • 2
    Когда вы говорите, что хотите «добавить нули», вы, вероятно, не хотите преобразовывать ваши целочисленные столбцы в строковые / категориальные, чтобы добавить заполнение нулями внутри самих данных, вы хотите оставить их целыми и вывести только начальные нули при рендеринге вывода .
Теги:
number-formatting
formatting
r-faq

7 ответов

353
Лучший ответ

Краткая версия: используйте formatC или sprintf.


Более длинная версия:

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

Пример из вопроса довольно прост, так как все значения имеют одинаковое количество цифр, поэтому попробуйте более сложный пример создания степеней 10 ширины 8.

anim <- 25499:25504
x <- 10 ^ (0:5)

paste (и его вариант paste0) часто являются первыми функциями манипуляции строкой, которые вы придете в поперечнике. Они не предназначены для управления числами, но они могут быть использованы для этого. В простом случае, когда нам всегда нужно добавить один ноль, paste0 - лучшее решение.

paste0("0", anim)
## [1] "025499" "025500" "025501" "025502" "025503" "025504"

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


str_pad из stringr работает аналогично paste, что делает его более явным, что вы хотите чтобы проложить вещи.

library(stringr)
str_pad(anim, 6, pad = "0")
## [1] "025499" "025500" "025501" "025502" "025503" "025504"

Опять же, он не предназначен для использования с цифрами, поэтому для более сложного случая требуется немного подумать. Мы должны просто сказать "pad с нулями до ширины 8", но посмотрите на этот вывод:

str_pad(x, 8, pad = "0")
## [1] "00000001" "00000010" "00000100" "00001000" "00010000" "0001e+05"

Вам нужно установить научный штраф option, чтобы числа всегда форматировались с использованием фиксированной нотации (а не научной нотации).

library(withr)
with_options(
  c(scipen = 999), 
  str_pad(x, 8, pad = "0")
)
## [1] "00000001" "00000010" "00000100" "00001000" "00010000" "00100000"

stri_pad в stringi работает точно так же, как str_pad от stringr.


formatC - это интерфейс к функции C printf. Использование этого требует некоторого знания арканы этой основной функции (см. Ссылку). В этом случае важными являются аргументы width, format "d" для "integer" и a "0" flag для добавления нулей.

formatC(anim, width = 6, format = "d", flag = "0")
## [1] "025499" "025500" "025501" "025502" "025503" "025504"
formatC(x, width = 8, format = "d", flag = "0")
## [1] "00000001" "00000010" "00000100" "00001000" "00010000" "00100000"

Это мое любимое решение, так как легко изменить работу с изменением ширины, и эта функция достаточно мощная, чтобы другие изменения форматирования.


sprintf - это интерфейс к функции C с тем же именем; например formatC, но с другим синтаксисом.

sprintf("%06d", anim)
## [1] "025499" "025500" "025501" "025502" "025503" "025504"
sprintf("%08d", x)
## [1] "00000001" "00000010" "00000100" "00001000" "00010000" "00100000"

Основным преимуществом sprintf является то, что вы можете вставлять форматированные числа в более длинные фрагменты текста.

sprintf(
  "Animal ID %06d was a %s.", 
  anim, 
  sample(c("lion", "tiger"), length(anim), replace = TRUE)
)
## [1] "Animal ID 025499 was a tiger." "Animal ID 025500 was a tiger."
## [3] "Animal ID 025501 was a lion."  "Animal ID 025502 was a tiger."
## [5] "Animal ID 025503 was a tiger." "Animal ID 025504 was a lion." 

См. также товарный ответ.


Для полноты стоит упомянуть другие функции форматирования, которые иногда полезны, но не имеют метода добавления нулей.

format - универсальная функция для форматирования любого объекта с методом для чисел. Он работает немного как formatC, но с еще одним интерфейсом.

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

Пакет scales имеет несколько функций, таких как percent, date_format и dollar для специальных типов форматов.

  • 2
    Большое спасибо за большую помощь. Я использовал formatC для добавления ведущих нулей к своему аниму, и это работало хорошо.
  • 2
    formatC (число или вектор, width = 6, format = "d", flag = "0") работал хорошо (версия R 3.0.2 (2013-09-25)). Благодарю.
Показать ещё 8 комментариев
180

Для общего решения, которое работает независимо от количества цифр в data$anim, используйте функцию sprintf. Он работает следующим образом:

sprintf("%04d", 1)
# [1] "0001"
sprintf("%04d", 104)
# [1] "0104"
sprintf("%010d", 104)
# [1] "0000000104"

В вашем случае вы, вероятно, захотите: data$anim <- sprintf("%06d", data$anim)

  • 14
    Обратите внимание, что sprintf преобразует число в строку (символ).
  • 0
    Спасибо за ответ. Я хочу сделать 13-значное число из 14-значным (добавляя начальный ноль). Эта функция не работает в этом случае. Это вызывает ошибку: ошибка в sprintf («% 020d», 4000100000104): неверный формат «% 020d»; используйте формат% f,% e,% g или% a для числовых объектов. Любое предложение?
Показать ещё 2 комментария
27

Расширение ответа @goodside:

В некоторых случаях вам может понадобиться заполнить строку нулями (например, коды fips или другие числовые факторы). В OSX/Linux:

> sprintf("%05s", "104")
[1] "00104"

Но поскольку sprintf() вызывает команду OS C sprintf(), обсуждаемую здесь, в Windows 7 вы получаете другой результат:

> sprintf("%05s", "104")
[1] "  104"

Итак, на машинах Windows работа вокруг:

> sprintf("%05d", as.numeric("104"))
[1] "00104"
  • 1
    По какой-то причине это решение больше не работает для меня в Linux. str_pad @ str_pad теперь мой.
16

str_pad из пакета stringr является альтернативой.

anim = 25499:25504
str_pad(anim, width=6, pad="0")
  • 1
    Будьте очень осторожны с str_pad как это может привести к неожиданным результатам. i.num = 600000 ; str_pad(i.num, width = 7, pad = "0") даст вам "006e + 05", а не "0600000"
1
data$anim <- sapply(0, paste0,data$anim)
0

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

Кто-то может найти это полезным:

idnamer<-function(x,y){#Alphabetical designation and number of integers required
    id<-c(1:y)
    for (i in 1:length(id)){
         if(nchar(id[i])<2){
            id[i]<-paste("0",id[i],sep="")
         }
    }
    id<-paste(x,id,sep="")
    return(id)
}
idnamer("EF",28)

Извините за форматирование.

  • 0
    Это будет работать, только если число достигает 100.
0

Вот еще одна альтернатива для добавления, ведущего к 0s в строки, такие как CUSIPs, которые иногда могут выглядеть как число, и многие приложения, такие как Excel будет повреждать и удалять ведущие 0s или преобразовывать их в научную нотацию.

Когда я попробовал ответ, предоставленный @metasequoia, возвращаемый вектор имел начальные пробелы, а не 0 s. Это была та же проблема, о которой упоминал @user1816679, - и удаление котировок вокруг 0 или изменение с %d на %s тоже не помогло. FYI, я использую RStudio Server, работающий на сервере Ubuntu. Это небольшое двухшаговое решение работало для меня:

gsub(pattern = " ", replacement = "0", x = sprintf(fmt = "%09s", ids[,CUSIP]))

используя функцию %>% pipe из пакета magrittr, она может выглядеть так:

sprintf(fmt = "%09s", ids[,CUSIP]) %>% gsub(pattern = " ", replacement = "0", x = .)

Я бы предпочел однофункциональное решение, но оно работает.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню