Come aggiungere zeri iniziali?


351

Ho un set di dati che assomiglia a questo:

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

Vorrei aggiungere uno zero prima di ogni ID animale:

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 per interesse, cosa succede se devo aggiungere due o tre zeri prima dell'ID dell'animale?


6
Supponiamo di voler aggiungere n zeri prima degli ID animali che devi solo faredata$anim = paste(rep(0, n), data$anim, sep = "")
Ramnath,

2
Quando si dice che si desidera "aggiungere zeri", presumibilmente non si desidera convertire le colonne di numeri interi in string / categoriale al fine di aggiungere il riempimento zero all'interno dei dati stessi, si desidera mantenerli interi e stampare solo zeri iniziali durante il rendering dell'output .
smci,

Risposte:


553

La versione breve: usa formatCo sprintf.


La versione più lunga:

Sono disponibili diverse funzioni per la formattazione dei numeri, inclusa l'aggiunta di zeri iniziali. Qual è il migliore dipende da quale altra formattazione vuoi fare.

L'esempio della domanda è abbastanza semplice poiché tutti i valori hanno lo stesso numero di cifre per cominciare, quindi proviamo un esempio più duro di fare anche poteri di 10 larghezza 8.

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

paste(e la sua variante paste0) sono spesso le prime funzioni di manipolazione delle stringhe che incontri. Non sono progettati per manipolare i numeri, ma possono essere usati per quello. Nel semplice caso in cui dobbiamo sempre anteporre un singolo zero, paste0è la soluzione migliore.

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

Nel caso in cui ci sia un numero variabile di cifre nei numeri, devi calcolare manualmente quanti zeri da anteporre, il che è abbastanza orribile che dovresti farlo solo per morbosa curiosità.


str_padda stringrfunziona in modo simile a paste, rendendo più esplicito che si desidera riempire le cose.

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

Ancora una volta, non è davvero progettato per l'uso con i numeri, quindi il caso più difficile richiede un piccolo pensiero. Dovremmo essere in grado di dire "pad con zero da 8", ma guarda questo output:

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

Devi impostare l' opzione penalità scientifica in modo che i numeri siano sempre formattati usando la notazione fissa (piuttosto che la notazione scientifica).

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

stri_padin stringifunziona esattamente come str_padda stringr.


formatCè un'interfaccia alla funzione C printf. Il suo utilizzo richiede una certa conoscenza degli arcani di quella funzione sottostante (vedi link). In questo caso, i punti importanti sono l' widthargomento, formatessendo "d""integer" e a "0" flagper anteporre zero.

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"

Questa è la mia soluzione preferita, poiché è facile armeggiare cambiando la larghezza e la funzione è abbastanza potente da apportare altre modifiche alla formattazione.


sprintfè un'interfaccia per la funzione C con lo stesso nome; come formatCma con una sintassi diversa.

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

Il vantaggio principale di sprintfè che puoi incorporare numeri formattati all'interno di bit di testo più lunghi.

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

Vedi anche la risposta di Goodside .


Per completezza vale la pena menzionare le altre funzioni di formattazione che sono occasionalmente utili, ma non hanno un metodo per anteporre zero.

format, una funzione generica per la formattazione di qualsiasi tipo di oggetto, con un metodo per i numeri. Funziona un po 'come formatC, ma con l'ennesima interfaccia.

prettyNumè ancora un'altra funzione di formattazione, principalmente per la creazione di etichette di tick dell'asse manuale. Funziona particolarmente bene per ampie gamme di numeri.

Il scalespacchetto ha diverse funzioni come percent, date_formate dollarper tipi di formati speciali.


3
grazie mille per l'ottimo aiuto. Ho usato formatC per aggiungere zeri iniziali al mio anim e ha funzionato bene.
baz,

2
formatC (numero o vettore, larghezza = 6, formato = "d", flag = "0") ha funzionato bene (R versione 3.0.2 (2013-09-25)). Grazie.
Mohamad Fakih,

1
usare formatC () nel modo sopra descritto non ha funzionato per me. Ha aggiunto spazi anziché zero. Ho fatto qualcosa di male? Sto usando R versione 3.1.1.
user1816679,

2
@ user1816679 Sembra che ti sei dimenticato flag = "0".
Richie Cotton,

1
La sezione Dettagli della ?sprintfpagina di aiuto lo descrive. "mn: due numeri separati da un punto, che indica la larghezza del campo (m) e la precisione (n)."
Richie Cotton,

215

Per una soluzione generale che funziona indipendentemente da quante cifre ci sono data$anim, utilizzare la sprintffunzione. Funziona così:

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

Nel tuo caso, probabilmente vuoi: data$anim <- sprintf("%06d", data$anim)


14
Nota che sprintfconverte numerico in stringa (carattere).
aL3xa,

Grazie per la risposta. Voglio fare un numero di 13 cifre a 14 cifre (aggiungendo zero iniziale). Questa funzione non sembra funzionare per questo caso. Mi dà un arror: Errore in sprintf ("% 020d", 4000100000104): formato non valido '% 020d'; usa il formato% f,% e,% go% a per gli oggetti numerici. Qualche suggerimento?
Rotail

Prova: sprintf ("% 014.0f", 4000100000104)
Stewart Macdonald

sprintf non è disponibile per R 3.4.1
Frank FYC

Sì. È invariato rispetto alla versione 1.5.0.
dash2

33

Espandendo la risposta di @ goodside:

In alcuni casi potresti voler riempire una stringa con zeri (ad esempio codici fips o altri fattori di tipo numerico). In OSX / Linux:

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

Ma poiché sprintf()chiama il sprintf()comando C del sistema operativo , discusso qui , in Windows 7 si ottiene un risultato diverso:

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

Quindi su macchine Windows il problema è:

> sprintf("%05d", as.numeric("104"))
[1] "00104"

1
Per qualsiasi motivo, questa soluzione non funziona più per me su Linux. @ Kdauria str_padè ora il mio andare a.
metasequoia,

25

str_paddal stringrpacchetto è un'alternativa.

anim = 25499:25504
str_pad(anim, width=6, pad="0")

4
Fai molta attenzione str_padperché può portare a risultati inaspettati. i.num = 600000; str_pad(i.num, width = 7, pad = "0") ti darà "006e + 05" e non "0600000"
Pankil Shah,

2

Ecco una funzione di base R generalizzabile:

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)

Mi piace sprintfma viene fornito con avvertenze come:

tuttavia l'implementazione effettiva seguirà lo standard C99 e i dettagli (in particolare il comportamento in caso di errore dell'utente) possono dipendere dalla piattaforma


1

Ecco un'altra alternativa per aggiungere lo zero iniziale a stringhe come CUSIP che a volte possono sembrare un numero e che molte applicazioni come Excel corromperanno e rimuoveranno gli 0 iniziali o li convertiranno in notazione scientifica.

Quando ho provato la risposta fornita da @metasequoia, il vettore restituito aveva spazi iniziali e non 0s. Questo era lo stesso problema menzionato da @ user1816679 - e anche la rimozione delle virgolette 0o la modifica da %da %snon faceva differenza. Cordiali saluti, sto usando RStudio Server in esecuzione su un server Ubuntu. Questa piccola soluzione in due passaggi ha funzionato per me:

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

usando la %>%funzione pipe dal magrittrpacchetto potrebbe apparire così:

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

Preferirei una soluzione a una funzione, ma funziona.


0
data$anim <- sapply(0, paste0,data$anim)

Funzionerebbe paste0(0, data$anim)bene.
dash2

0

Per altre circostanze in cui vuoi che la stringa numerica sia coerente, ho creato una funzione.

Qualcuno potrebbe trovarlo utile:

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)

Mi dispiace per la formattazione.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.