¿Cómo agregar ceros a la izquierda?

351

Tengo un conjunto de datos que se parece a esto:

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

Me gustaría agregar un cero antes de cada identificación 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

Y por interés, ¿qué pasa si necesito agregar dos o tres ceros antes de la identificación del animal?

baz
fuente
66
Supongamos que desea agregar n ceros antes de los identificadores de animales que solo necesita hacerdata$anim = paste(rep(0, n), data$anim, sep = "")
Ramnath
2
Cuando dice que desea "agregar ceros", presumiblemente no desea convertir sus columnas enteras en cadenas / categóricas para agregar el relleno de ceros dentro de los datos, desea mantenerlos enteros e imprimir solo ceros iniciales al renderizar la salida .
smci

Respuestas:

553

La versión corta: use formatCo sprintf.


La versión más larga:

Hay varias funciones disponibles para formatear números, incluida la adición de ceros a la izquierda. Cuál es el mejor depende de qué otro formato desea hacer.

El ejemplo de la pregunta es bastante fácil ya que todos los valores tienen el mismo número de dígitos para comenzar, así que intentemos un ejemplo más difícil de hacer potencias de 10 ancho 8 también.

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

paste(y su variante paste0) son a menudo las primeras funciones de manipulación de cadenas que se encuentran. Realmente no están diseñados para manipular números, pero pueden usarse para eso. En el caso simple donde siempre tenemos que anteponer un solo cero, paste0es la mejor solución.

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

Para el caso donde hay un número variable de dígitos en los números, debe calcular manualmente cuántos ceros anteponer, lo cual es lo suficientemente horrible como para hacerlo solo por curiosidad mórbida.


str_padfrom stringrfunciona de manera similar a paste, lo que hace más explícito que desea rellenar las cosas.

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

Nuevamente, no está realmente diseñado para su uso con números, por lo que el caso más difícil requiere un poco de reflexión. Deberíamos poder decir "pad con ceros a ancho 8", pero mira esta salida:

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

Debe configurar la opción de penalización científica para que los números siempre estén formateados con notación fija (en lugar de notación científica).

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

stri_paden stringitrabajos exactamente como str_padde stringr.


formatCes una interfaz a la función C printf. Su uso requiere cierto conocimiento de los arcanos de esa función subyacente (ver enlace). En este caso, los puntos importantes son el widthargumento, que formates "d"para "entero" y a "0" flagpara preceder ceros.

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 es mi solución favorita, ya que es fácil jugar con el cambio de ancho, y la función es lo suficientemente potente como para hacer otros cambios de formato.


sprintfes una interfaz para la función C del mismo nombre; como formatCpero con una sintaxis diferente.

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

La principal ventaja de sprintfes que puede incrustar números formateados dentro de fragmentos de texto más largos.

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

Ver también la respuesta de Goodside .


Para completar, vale la pena mencionar las otras funciones de formato que ocasionalmente son útiles, pero que no tienen un método de anteponer ceros.

format, una función genérica para formatear cualquier tipo de objeto, con un método para números. Funciona un poco como formatC, pero con otra interfaz más.

prettyNumes otra función de formato, principalmente para crear etiquetas de marca de eje manuales. Funciona particularmente bien para amplios rangos de números.

El scalespaquete tiene varias funciones como percent, date_formaty dollarpara tipos de formatos especializados.

Algodón Richie
fuente
3
Muchas gracias por la gran ayuda. Usé formatC para agregar ceros iniciales a mi anim y funcionó bien.
baz
2
formatC (número o vector, ancho = 6, formato = "d", bandera = "0") funcionó bien (R versión 3.0.2 (2013-09-25)). Gracias.
Mohamad Fakih
1
El uso de formatC () en la forma descrita anteriormente no funcionó para mí. Agregó espacios en lugar de ceros. ¿Hice algo mal? Estoy usando R versión 3.1.1.
user1816679
2
@ user1816679 Suena como si lo hubieras olvidado flag = "0".
Richie Cotton
1
La sección Detalles de la ?sprintfpágina de ayuda describe esto. "mn: Dos números separados por un punto, que denotan el ancho del campo (m) y la precisión (n)".
Richie Cotton
215

Para una solución general que funcione independientemente de cuántos dígitos haya data$anim, use la sprintffunción. Funciona así:

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

En tu caso, probablemente quieras: data$anim <- sprintf("%06d", data$anim)

buen lado
fuente
14
Tenga en cuenta que sprintfconvierte numérico a cadena (carácter).
aL3xa
Gracias por la respuesta. Quiero hacer un número de 13 dígitos a 14 dígitos (agregando cero a la izquierda). Esta función no parece funcionar para este caso. Me da un error: error en sprintf ("% 020d", 4000100000104): formato no válido '% 020d'; use el formato% f,% e,% go% a para objetos numéricos. ¿Cualquier sugerencia?
Rotail
Prueba: sprintf ("% 014.0f", 4000100000104)
Stewart Macdonald
sprintf no está disponible para R 3.4.1
Frank FYC
Sí lo es. No ha cambiado desde la versión 1.5.0.
dash2
33

Ampliando la respuesta de @ goodside:

En algunos casos, es posible que desee rellenar una cadena con ceros (por ejemplo, códigos fips u otros factores numéricos). En OSX / Linux:

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

Pero debido a que sprintf()llama al sprintf()comando C del sistema operativo , discutido aquí , en Windows 7 obtienes un resultado diferente:

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

Entonces, en máquinas Windows, la solución es:

> sprintf("%05d", as.numeric("104"))
[1] "00104"
metasequoia
fuente
1
Por alguna razón, esta solución ya no funciona para mí en Linux. @ kdauria str_pades ahora mi ir a.
metasequoia
25

str_paddel stringrpaquete es una alternativa.

anim = 25499:25504
str_pad(anim, width=6, pad="0")
kdauria
fuente
44
Tenga mucho cuidado str_padya que puede conducir a resultados inesperados. i.num = 600000; str_pad(i.num, width = 7, pad = "0") le dará "006e + 05" y no "0600000"
Pankil Shah
2

Aquí hay una función base R generalizable:

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)

Me gusta sprintfpero viene con advertencias como:

sin embargo, la implementación real seguirá el estándar C99 y los detalles finos (especialmente el comportamiento bajo error del usuario) pueden depender de la plataforma

Tyler Rinker
fuente
1

Aquí hay otra alternativa para agregar los primeros ceros a cadenas como CUSIP que a veces puede parecer un número y que muchas aplicaciones como Excel corromperán y eliminarán los ceros a la izquierda o los convertirán a notación científica.

Cuando probé la respuesta proporcionada por @metasequoia, el vector devuelto tenía espacios iniciales y no 0s. Este fue el mismo problema mencionado por @ user1816679, y eliminar las comillas 0o cambiar de %da %stampoco marcó la diferencia. FYI, estoy usando RStudio Server ejecutándose en un servidor Ubuntu. Esta pequeña solución de dos pasos me funcionó:

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

usando la %>%función de tubería del magrittrpaquete podría verse así:

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

Prefiero una solución de una función, pero funciona.

Ursus Frost
fuente
0
data$anim <- sapply(0, paste0,data$anim)
zhan2383
fuente
Solo paste0(0, data$anim)funcionaría bien.
dash2
0

Para otras circunstancias en las que desea que la cadena numérica sea coherente, hice una función.

Alguien puede encontrar esto ú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)

Perdón por el formato.

Phil
fuente