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

352

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

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

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

Baz
источник
6
Предположим, что вы хотите добавить n нулей перед идентификаторами животных, которые вам просто нужно сделатьdata$anim = paste(rep(0, n), data$anim, sep = "")
Ramnath
2
Когда вы говорите, что хотите «добавить нули», вы, вероятно, не хотите преобразовывать целочисленные столбцы в строковые / категориальные, чтобы добавить заполнение нулями внутри самих данных, вы хотите оставить их целыми и вывести только начальные нули. при рендеринге вывода .
SMCI

Ответы:

555

Краткая версия: используйте 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 with zeroes to width 8», но посмотрим на этот вывод:

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

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

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"на «целое», и "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для специалистов типов форматов.

Ричи Коттон
источник
3
Большое спасибо за большую помощь. Я использовал formatC, чтобы добавить ведущие нули к своему аниму, и это работало хорошо.
Баз
2
Формат C (число или вектор, ширина = 6, формат = "d", флаг = "0") работал хорошо (версия R 3.0.2 (2013-09-25)). Спасибо.
Мохамад Факих
1
использование formatC () описанным выше способом не работает для меня. Это добавило пробелы вместо нулей. Я сделал что-то не так? Я использую R версии 3.1.1.
user1816679
2
@ user1816679 Звучит так, как будто ты забыл flag = "0".
Ричи Коттон
1
Раздел Подробности на ?sprintfстранице справки описывает это. «mn: два числа, разделенные точкой, обозначающие ширину поля (m) и точность (n)».
Ричи Коттон
215

Для общего решения, которое работает независимо от количества цифр 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преобразует число в строку (символ).
aL3xa
Спасибо за ответ. Я хочу сделать 13-значное число из 14-значным (добавляя начальный ноль). Эта функция не работает в этом случае. Это вызывает ошибку: ошибка в sprintf ("% 020d", 4000100000104): неверный формат "% 020d"; используйте формат% f,% e,% g или% a для числовых объектов. Любое предложение?
Rotail
Попробуйте: sprintf ("% 014.0f", 4000100000104)
Стюарт Макдональд
sprintf недоступен для R 3.4.1
Франк FYC
Да, это так. Это не изменилось с версии 1.5.0.
dash2
33

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

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

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

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

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

Итак, на компьютерах с Windows обходной путь:

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

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

anim = 25499:25504
str_pad(anim, width=6, pad="0")
kdauria
источник
4
Будьте очень осторожны, так str_padкак это может привести к неожиданным результатам. i.num = 600000; str_pad(i.num, width = 7, pad = "0") даст вам «006e + 05», а не «0600000»
Панкил Шах
2

Вот обобщаемая базовая функция R:

pad_left <- function(x, len = 1 + max(nchar(x)), char = '0'){

    unlist(lapply(x, function(x) {
        paste0(
            paste(rep(char, len - nchar(x)), collapse = ''),
            x
        )
    }))
}

pad_left(1:100)

Мне нравится, sprintfно это идет с оговорками, такими как:

однако фактическая реализация будет следовать стандарту C99, и мелкие детали (особенно поведение при ошибке пользователя) могут зависеть от платформы

Тайлер Ринкер
источник
1

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

Когда я попробовал ответ, предоставленный @metasequoia, у возвращаемого вектора были начальные пробелы, а не 0s. Это была та же проблема, о которой упоминал @ user1816679 - и удаление кавычек вокруг 0или изменение с %dна также %sничего не изменило . К вашему сведению, я использую 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 = .)

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

Урсус Фрост
источник
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)

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

Фил
источник