Comment ajouter des zéros non significatifs?

351

J'ai un ensemble de données qui ressemble à ceci:

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

J'aimerais qu'un zéro soit ajouté avant chaque identifiant d'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

Et dans l'intérêt, que se passe-t-il si j'ai besoin d'ajouter deux ou trois zéros avant l'identification de l'animal?

baz
la source
6
Supposons que vous vouliez ajouter n zéros avant les identifiants d'animaux que vous avez juste à fairedata$anim = paste(rep(0, n), data$anim, sep = "")
Ramnath
2
Lorsque vous dites que vous voulez "ajouter des zéros", vous ne voulez probablement pas convertir vos colonnes entières en chaîne / catégorique afin d'ajouter le remplissage nul à l'intérieur des données elles-mêmes, vous voulez les garder entières et n'imprimer que les zéros de tête lors du rendu de la sortie .
smci

Réponses:

554

La version courte: utilisez formatCou sprintf.


La version plus longue:

Plusieurs fonctions sont disponibles pour formater les nombres, notamment l'ajout de zéros non significatifs. Le meilleur choix dépend du formatage que vous souhaitez effectuer.

L'exemple de la question est assez facile car toutes les valeurs ont le même nombre de chiffres pour commencer, alors essayons un exemple plus difficile de faire des puissances de 10 largeur 8 aussi.

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

paste(et sa variante paste0) sont souvent les premières fonctions de manipulation de chaînes que vous rencontrez. Ils ne sont pas vraiment conçus pour manipuler des nombres, mais ils peuvent être utilisés pour cela. Dans le cas simple où nous devons toujours ajouter un seul zéro, paste0c'est la meilleure solution.

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

Dans le cas où il y a un nombre variable de chiffres dans les nombres, vous devez calculer manuellement le nombre de zéros à ajouter, ce qui est suffisamment horrible pour que vous ne le fassiez que par curiosité morbide.


str_padà partir de stringrtravaux similaires à paste, ce qui rend plus explicite le fait que vous souhaitez remplir les choses.

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

Encore une fois, il n'est pas vraiment conçu pour être utilisé avec des chiffres, donc le cas le plus difficile nécessite un peu de réflexion. On devrait juste pouvoir dire "pad avec des zéros de largeur 8", mais regardez cette sortie:

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

Vous devez définir l' option de pénalité scientifique afin que les nombres soient toujours formatés en utilisant une notation fixe (plutôt que la notation scientifique).

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

stri_paddans des stringiœuvres exactement comme à str_padpartir de stringr.


formatCest une interface pour la fonction C printf. Son utilisation nécessite une certaine connaissance des arcanes de cette fonction sous-jacente (voir lien). Dans ce cas, les points importants sont l' widthargument, formatétant "d"pour "entier", et un "0" flagpour les zéros au début.

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"

C'est ma solution préférée, car il est facile de bricoler en changeant la largeur et la fonction est suffisamment puissante pour effectuer d'autres changements de mise en forme.


sprintfest une interface vers la fonction C du même nom; commeformatC mais avec une syntaxe différente.

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

Le principal avantage de sprintf est que vous pouvez intégrer des nombres formatés dans des morceaux de texte plus longs.

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

Voir également la réponse de goodside .


Par souci d'exhaustivité, il convient de mentionner les autres fonctions de formatage qui sont parfois utiles, mais n'ont pas de méthode pour ajouter des zéros.

format, une fonction générique pour formater tout type d'objet, avec une méthode pour les nombres. Cela fonctionne un peu comme formatC, mais avec encore une autre interface.

prettyNumest encore une autre fonction de formatage, principalement pour créer des étiquettes de tick d'axe manuel. Il fonctionne particulièrement bien pour de larges plages de nombres.

Le scalespaquet a plusieurs fonctions telles que percent, date_formatet dollarpour les types de format spécialisés.

Richie Cotton
la source
3
merci beaucoup pour la grande aide. J'ai utilisé formatC pour ajouter des zéros de tête à mon anim et cela a bien fonctionné.
baz
2
formatC (nombre ou vecteur, largeur = 6, format = "d", drapeau = "0") a bien fonctionné (R version 3.0.2 (2013-09-25)). Merci.
Mohamad Fakih,
1
utiliser formatC () de la manière décrite ci-dessus n'a pas fonctionné pour moi. Il a ajouté des espaces au lieu de zéros. Est-ce que j'ai fait quelque chose de mal? J'utilise la version R 3.1.1.
user1816679
2
@ user1816679 On dirait que vous avez oublié flag = "0".
Richie Cotton
1
La section Détails de la ?sprintfpage d'aide décrit cela. "mn: deux nombres séparés par un point, indiquant la largeur du champ (m) et la précision (n)."
Richie Cotton
215

Pour une solution générale qui fonctionne quel que soit le nombre de chiffres data$anim , utilisez la sprintffonction. Cela fonctionne comme ceci:

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

Dans votre cas, vous voulez probablement: data$anim <- sprintf("%06d", data$anim)

bon côté
la source
14
Notez que sprintfconvertit le numérique en chaîne (caractère).
aL3xa
Merci d'avoir répondu. Je veux faire un nombre de 13 chiffres à 14 chiffres (en ajoutant zéro à gauche). Cette fonction ne semble pas fonctionner dans ce cas. Cela me donne une arror: Erreur dans sprintf ("% 020d", 4000100000104): format invalide '% 020d'; utilisez le format% f,% e,% g ou% a pour les objets numériques. Toute suggestion?
Rotail
Essayez: sprintf ("% 014.0f", 4000100000104)
Stewart Macdonald
sprintf n'est pas disponible pour R 3.4.1
Frank FYC
Oui, ça l'est. Il est inchangé depuis la version 1.5.0.
dash2
33

Étendre la réponse de @ goodside:

Dans certains cas, vous souhaiterez peut-être remplir une chaîne avec des zéros (par exemple des codes fips ou d'autres facteurs de type numérique). Sous OSX / Linux:

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

Mais comme sprintf()la sprintf()commande C du système d'exploitation , décrite ici , dans Windows 7, vous obtenez un résultat différent:

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

Donc, sur les machines Windows, le travail est:

> sprintf("%05d", as.numeric("104"))
[1] "00104"
metasequoia
la source
1
Pour une raison quelconque, cette solution ne fonctionne plus pour moi sur Linux. @ kdauria str_padest maintenant mon rendez-vous.
metasequoia
25

str_padde l' stringremballage est une alternative.

anim = 25499:25504
str_pad(anim, width=6, pad="0")
kdauria
la source
4
Soyez très prudent str_padcar cela peut conduire à des résultats inattendus. i.num = 600000; str_pad(i.num, width = 7, pad = "0") vous donnera "006e + 05" et non "0600000"
Pankil Shah
2

Voici une fonction R de base généralisable:

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)

J'aime sprintfmais il est livré avec des mises en garde comme:

cependant, l'implémentation réelle suivra la norme C99 et les détails fins (en particulier le comportement en cas d'erreur de l'utilisateur) peuvent dépendre de la plate-forme

Tyler Rinker
la source
1

Voici une autre alternative pour ajouter menant à 0 à des chaînes telles que CUSIP qui peuvent parfois ressembler à un nombre et que de nombreuses applications comme Excel corrompent et suppriment les 0 à gauche ou les convertissent en notation scientifique.

Lorsque j'ai essayé la réponse fournie par @metasequoia, le vecteur renvoyé avait des espaces de tête et non 0s. C'était le même problème mentionné par @ user1816679 - et la suppression des guillemets autour de 0ou la modification de %dà %sne faisait aucune différence non plus. Pour info, j'utilise RStudio Server fonctionnant sur un serveur Ubuntu. Cette petite solution en deux étapes a fonctionné pour moi:

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

en utilisant la %>%fonction pipe du magrittrpackage, cela pourrait ressembler à ceci:

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

Je préférerais une solution à une fonction, mais cela fonctionne.

Ursus Frost
la source
0
data$anim <- sapply(0, paste0,data$anim)
zhan2383
la source
Ça paste0(0, data$anim)marcherait bien.
dash2
0

Pour d'autres circonstances dans lesquelles vous souhaitez que la chaîne numérique soit cohérente, j'ai créé une fonction.

Quelqu'un peut trouver cela 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)

Désolé pour le formatage.

Phil
la source