Como adicionar zeros à esquerda?

351

Eu tenho um conjunto de dados que se parece com isso:

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

Eu gostaria que um zero fosse adicionado antes de cada ID de animal:

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

E pelo interesse, e se eu precisar adicionar dois ou três zeros antes da identificação do animal?

baz
fonte
6
Suponha que você deseja adicionar n zeros antes ids animais que você só precisa fazerdata$anim = paste(rep(0, n), data$anim, sep = "")
Ramnath
2
Quando você diz que deseja "adicionar zeros", presumivelmente não deseja converter suas colunas inteiras em string / categórica, a fim de adicionar o preenchimento zero aos próprios dados, deseja mantê-los inteiros e imprimir apenas zeros à esquerda ao renderizar saída .
smci 11/09/15

Respostas:

553

A versão curta: use formatCou sprintf.


A versão mais longa:

Existem várias funções disponíveis para formatar números, incluindo a adição de zeros à esquerda. Qual é o melhor depende de qual outra formatação você deseja fazer.

O exemplo da pergunta é bastante fácil, já que todos os valores têm o mesmo número de dígitos, portanto, vamos tentar um exemplo mais difícil de criar potências de 10 de largura 8 também.

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

paste(e sua variante paste0) geralmente são as primeiras funções de manipulação de strings que você encontra. Eles não são realmente projetados para manipular números, mas podem ser usados ​​para isso. No caso simples, em que sempre precisamos acrescentar um único zero, paste0é a melhor solução.

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

No caso em que há um número variável de dígitos nos números, é necessário calcular manualmente quantos zeros devem ser acrescentados, o que é horrível o suficiente para que você deva fazê-lo apenas por curiosidade mórbida.


str_padde stringrobras de forma semelhante a paste, tornando-a mais explícita que você quer coisas almofada.

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

Novamente, ele não foi realmente projetado para uso com números, portanto, o caso mais difícil exige um pouco de reflexão. Deveríamos apenas poder dizer "almofada com zeros na largura 8", mas veja esta saída:

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

Você precisa definir a opção de penalidade científica para que os números sejam sempre formatados usando notação fixa (em vez de notação científica).

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

stri_padem stringiobras exatamente como str_padde stringr.


formatCé uma interface para a função C printf. Usá-lo requer algum conhecimento dos arcanos dessa função subjacente (consulte o link). Nesse caso, os pontos importantes são o widthargumento, formatsendo "d"para "número inteiro" e um "0" flagpara preceder zeros.

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"

Esta é a minha solução favorita, pois é fácil mexer na alteração da largura e a função é poderosa o suficiente para fazer outras alterações na formatação.


sprintfé uma interface para a função C com o mesmo nome; como formatC, mas com uma sintaxe diferente.

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

A principal vantagem sprintfé que você pode incorporar números formatados em bits de texto mais longos.

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." 

Veja também a resposta da mercadoria .


Para completar, vale a pena mencionar as outras funções de formatação que são úteis ocasionalmente, mas não têm método de preceder zeros.

format, uma função genérica para formatar qualquer tipo de objeto, com um método para números. Funciona um pouco como formatC, mas com outra interface.

prettyNumé mais uma função de formatação, principalmente para a criação de rótulos de marcação de eixo manuais. Funciona particularmente bem para amplas faixas de números.

O scalespacote possui várias funções, como percent, date_formate dollarpara tipos de formato especializados.

Richie Cotton
fonte
3
muito obrigado pela grande ajuda. Usei o formatC para adicionar zeros à esquerda no meu anim e funcionou bem.
Baz
2
formatC (número ou vetor, largura = 6, formato = "d", sinalizador = "0") funcionou bem (versão R 3.0.2 (25-09-2013)). Obrigado.
Mohamad Fakih
11
usar formatC () da maneira descrita acima não funcionou para mim. Adicionou espaços em vez de zeros. Fiz algo de errado? Estou usando o R versão 3.1.1.
user1816679
2
@ user1816679 Parece que você esqueceu flag = "0".
Richie Cotton
11
A seção Detalhes da ?sprintfpágina de ajuda descreve isso. "mn: dois números separados por um ponto, indicando a largura do campo (m) e a precisão (n)."
Richie Cotton
215

Para uma solução geral que funcione independentemente de quantos dígitos estejam data$anim, use a sprintffunção Funciona assim:

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

No seu caso, você provavelmente quer: data$anim <- sprintf("%06d", data$anim)

lado bom
fonte
14
Observe que sprintfconverte numérico em sequência (caractere).
aL3xa
Obrigado pela resposta. Eu quero fazer um número de 13 dígitos para 14 dígitos (adicionando zero à esquerda). Esta função parece não funcionar para este caso. Isso me dá um erro: Erro no sprintf ("% 020d", 4000100000104): formato inválido '% 020d'; use o formato% f,% e,% g ou% a para objetos numéricos. Alguma sugestão?
Rotail
Tente: sprintf ("% 014.0f", 4000100000104)
Stewart Macdonald
sprintf não está disponível para R 3.4.1
Frank FYC
Sim, ele é. É inalterado desde a versão 1.5.0.
dash2 6/06
32

Expandindo a repsonse da @ goodside:

Em alguns casos, convém preencher uma string com zeros (por exemplo, códigos de fips ou outros fatores numéricos). No OSX / Linux:

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

Mas como sprintf()chama o sprintf()comando C do sistema operacional , discutido aqui , no Windows 7, você obtém um resultado diferente:

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

Portanto, em máquinas Windows, a solução é:

> sprintf("%05d", as.numeric("104"))
[1] "00104"
metasequoia
fonte
11
Por qualquer motivo, esta solução não funciona mais para mim no Linux. @ kdauria str_padagora é minha vez.
9136 metasequoia
25

str_paddo stringrpacote é uma alternativa.

anim = 25499:25504
str_pad(anim, width=6, pad="0")
kdauria
fonte
4
Tenha muito cuidado str_pad, pois pode levar a resultados inesperados. i.num = 600000; str_pad(i.num, width = 7, pad = "0") lhe dará "006e + 05" e não "0600000"
Pankil Shah
2

Aqui está uma função R generalizável de base:

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)

Eu gosto, sprintfmas ele vem com advertências como:

no entanto, a implementação real seguirá o padrão C99 e detalhes finos (especialmente o comportamento sob erro do usuário) podem depender da plataforma

Tyler Rinker
fonte
1

Aqui está outra alternativa para adicionar os 0s iniciais às seqüências de caracteres, como CUSIPs, que às vezes podem parecer um número e que muitos aplicativos, como o Excel, corromperão e removerão os 0s principais ou os converterão em notação científica.

Quando tentei a resposta fornecida pelo @metasequoia, o vetor retornado tinha espaços à esquerda e não 0s. Esse foi o mesmo problema mencionado por @ user1816679 - remover as aspas ao redor 0ou mudar de %dpara %stambém não fez diferença. Para sua informação, estou usando o RStudio Server em execução no Ubuntu Server. Esta pequena solução em duas etapas funcionou para mim:

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

usando a %>%função pipe da magrittrembalagem, ele pode ficar assim:

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

Eu preferiria uma solução de função única, mas funciona.

Ursus Frost
fonte
0
data$anim <- sapply(0, paste0,data$anim)
zhan2383
fonte
Apenas paste0(0, data$anim)funcionaria bem.
dash2 6/06
0

Para outras circunstâncias em que você deseja que a sequência numérica seja consistente, criei uma função.

Alguém pode achar isso útil:

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)

Desculpe a formatação.

Phil
fonte