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

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

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

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


person baz    schedule 28.04.2011    source источник
comment
Предположим, вы хотите добавить n нулей перед идентификаторами животных, вам просто нужно сделать data$anim = paste(rep(0, n), data$anim, sep = "")   -  person Ramnath    schedule 28.04.2011
comment
Когда вы говорите, что хотите добавить нули, вы, вероятно, не хотите преобразовывать свои целочисленные столбцы в строковые / категориальные, чтобы добавить нулевое заполнение внутри самих данных, вы хотите, чтобы они были целыми и только выводились нули при рендеринге вывода.   -  person smci    schedule 11.09.2015


Ответы (7)


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


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

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

Пример из вопроса довольно прост, поскольку все значения имеют одинаковое количество цифр в начале, поэтому давайте попробуем более сложный пример создания степеней 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"

Опять же, он на самом деле не предназначен для использования с числами, поэтому более сложный случай требует некоторого размышления. Мы должны просто иметь возможность сказать «набивка с нулями до ширины 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 _ 19_. Для его использования требуется некоторое знание тайн этой базовой функции (см. Ссылку). В этом случае важными моментами являются 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." 

См. Также ответ goodside.


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

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

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

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

person Richie Cotton    schedule 28.04.2011
comment
Большое спасибо за большую помощь. Я использовал formatC, чтобы добавить начальные нули к своему анимации, и это хорошо сработало. - person baz; 28.04.2011
comment
formatC (число или вектор, ширина = 6, формат = d, флаг = 0) работал хорошо (R версия 3.0.2 (2013-09-25)). Спасибо. - person Mohamad Fakih; 08.10.2013
comment
использование formatC () описанным выше способом у меня не сработало. Он добавил пробелы вместо нулей. Я сделал что-то не так? Я использую R версии 3.1.1. - person user1816679; 15.09.2014
comment
@ user1816679 Похоже, вы забыли flag = "0". - person Richie Cotton; 15.09.2014
comment
Неа. Ввод: formatC('1', width = 3, format = 'd', flag = '0') Вывод: [1] " 1" Редактировать: Я пробовал без кавычек, и это сработало. - person user1816679; 15.09.2014
comment
formatC предназначен для форматирования чисел. Если вы передадите ему строку, то, конечно, получите неожиданный результат. Функция действительно должна предупреждать о получении глупого ввода. - person Richie Cotton; 16.09.2014
comment
Спасибо, что перечислили все возможности, даже если они кажутся одинаковыми. Я хотел увеличить свои числа до одинаковой ширины, независимо от того, сколько их у меня, и я смог использовать для этого formatC с width=ceiling(log(nr.vars, base=10)). Я бы не смог сделать это с синтаксисом printf (или, если есть способ, я его не знаю). - person rumtscho; 06.06.2016
comment
@rumtscho Попробуй sprintf("%8.2f", 10 ^ (1:10)). Кроме того, log10 проще, чем log(base = 10). - person Richie Cotton; 08.06.2016
comment
@RichieCotton Я должен признать, что почти ничего не знаю о синтаксисе sprintf. Как работает ваше предложение и, что наиболее важно, где взять переменную, определяющую, сколько нулей использовать? - person rumtscho; 08.06.2016
comment
Это описано в разделе "Подробности" на странице справки ?sprintf. m.n: два числа, разделенных точкой, обозначающих ширину поля (m) и точность (n). - person Richie Cotton; 09.06.2016

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

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

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

person goodside    schedule 28.04.2011
comment
Обратите внимание, что sprintf преобразует число в строку (символ). - person aL3xa; 28.04.2011
comment
Спасибо за ответ. Я хочу преобразовать 13-значное число в 14-значное (добавив начальный ноль). В данном случае эта функция не работает. Это дает мне ошибку: Ошибка в sprintf (% 020d, 4000100000104): недопустимый формат '% 020d'; используйте формат% f,% e,% g или% a для числовых объектов. Любое предложение? - person Rotail; 04.08.2016
comment
Попробуйте: sprintf (% 014.0f, 4000100000104) - person Stewart Macdonald; 22.09.2016
comment
sprintf недоступен для R 3.4.1 - person Bluebird; 20.09.2017
comment
Да, это так. Он не изменился с версии 1.5.0. - person dash2; 06.06.2020
comment
У меня был странный опыт, когда коллега, использующий Windows, sprintf( печатал ведущие пробелы, в то время как мой Mac печатал ведущие нули. Мы перешли на stringr::str_pad( - person gregmacfarlane; 17.03.2021

Расширяя ответ @ 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"
person metasequoia    schedule 21.08.2013
comment
По какой-то причине это решение больше не работает в Linux. str_pad от @kdauria теперь мне нужен. - person metasequoia; 09.07.2016

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

anim = 25499:25504
str_pad(anim, width=6, pad="0")
person kdauria    schedule 27.08.2014
comment
Будьте очень осторожны с str_pad, так как это может привести к неожиданным результатам. i.num = 600000; str_pad(i.num, width = 7, pad = "0") даст вам 006e + 05, а не 0600000 - person Pankil Shah; 19.06.2017

Вот обобщенная базовая функция 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, и мелкие детали (особенно поведение при ошибке пользователя) могут зависеть от платформы.

person Tyler Rinker    schedule 27.09.2018

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

Когда я попробовал ответ, предоставленный @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 = .)

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

person Ursus Frost    schedule 10.12.2016

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

Кому-то это может пригодиться:

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)

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

person Phil    schedule 03.04.2017