R'de yüzde olarak bir sayı nasıl biçimlendirilir?


135

Eskiden R'ye yeni gelen biri olarak beni şaşırtan şeylerden biri, bir sayının yazdırma için yüzde olarak nasıl biçimlendirileceğiydi.

Örneğin, görüntüler 0.12345olarak 12.345%. Bunun için birkaç çözümüm var, ancak bunların hiçbiri "yeni dostça" görünmüyor. Örneğin:

set.seed(1)
m <- runif(5)

paste(round(100*m, 2), "%", sep="")
[1] "26.55%" "37.21%" "57.29%" "90.82%" "20.17%"

sprintf("%1.2f%%", 100*m)
[1] "26.55%" "37.21%" "57.29%" "90.82%" "20.17%"

Soru: Bunu yapmak için temel bir R işlevi var mı? Alternatif olarak, kullanışlı bir ambalaj sağlayan ve yaygın olarak kullanılan bir paket var mı?


Bu in gibi bir şey ararken rağmen ?format, ?formatCve ?prettyNumben R. tabanında uygun bir şekilde uygun sarmalayıcı bulmak için henüz ??"percent"yararlı bir şey vermemiştir. library(sos); findFn("format percent")1250 isabet döndürür - bu yüzden yine kullanışlı değildir. ggplot2bir işleve sahiptir, percentancak bu, yuvarlama doğruluğu üzerinde hiçbir kontrol sağlamaz.


5
sprintfposta listelerinde favori çözüm gibi görünüyor ve daha iyi bir çözüm görmedim. Herhangi bir yerleşik işlevi aramak daha kolay olmayacak, değil mi?
michel-slm

1
Benim görüşüme göre sprintf, aynı zamanda programcılar da olan bu R kodlayıcıları alt kümesi için mükemmel. Hayatımda COBOL (titreme) ve fortran (yaşımı gösterir) dahil olmak üzere pek çok kod yazdım. Ancak sprintfbiçimlendirme kurallarının açık olduğunu düşünmüyorum (çeviri: WTF?). Ve elbette özel bir paketleyiciyi aramak sprintf'ten daha kolay olmalı, örneğin:format_percent(x=0.12345, digits=2)
Andrie

@hircus Bence kendi kısa curried işlevini hak etmesi yeterince yaygın. Bu özellikle Sweave ile ilgili bir sorun, burada \ Sexpr {sprintf (% 1.2f %% ", myvar)}, \ Sexpr {pct (myvar)} veya daha kısa işlev ne olursa olsun çok daha çirkin.
Ari B. Friedman

2
Uygun araçları kullanmayı öğrenmek, kullanıcıların ulaşmak için çabalamasını beklememiz gereken bir şey değil mi? Demek istediğim, kullanmayı öğrenmek, foosprintf() paketinin içerdiğini bulmaktan daha fazla zaman alıcı değildir . Kullanıcı yüzde olarak biçimlendirmek istemezse ancak benzer başka bir şey olursa ne olur? Başka bir ambalaj bulmaları gerekiyor. Uzun vadede, temel araçları öğrenmek faydalı olacaktır. format_percent()
Gavin Simpson

1
%R için "varsayılan" raporlama formatı olan LaTeX'teki yorum karakterinde küçük bir sorun var. Bu nedenle, grafiklerin etiketlenmesi için yararlı olsa da, formatlanmış sayı Sweaved olacaksa dikkatli olunmalıdır.
James

Yanıtlar:


118

Daha sonra bile:

@DzimitryM'in belirttiği gibi , eski ile eşanlamlı olan percent()lehine "emekli" olmuştur.label_percent()percent_format() işlevin .

label_percent() bir işlev döndürür, bu yüzden onu kullanmak için fazladan bir çift parantez gerekir.

library(scales)
x <- c(-1, 0, 0.1, 0.555555, 1, 100)
label_percent()(x)
## [1] "-100%"   "0%"      "10%"     "56%"     "100%"    "10 000%"

İlk parantez kümesinin içine bağımsız değişkenler ekleyerek bunu özelleştirin.

label_percent(big.mark = ",", suffix = " percent")(x)
## [1] "-100 percent"   "0 percent"      "10 percent"    
## [4] "56 percent"     "100 percent"    "10,000 percent"

Birkaç yıl sonra bir güncelleme:

Bu günlerde bir percentscalesKrlmlr'in cevabında belirtildiği gibi, pakette işlev var. El yapımı çözümüm yerine bunu kullan.


Gibi bir şey dene

percent <- function(x, digits = 2, format = "f", ...) {
  paste0(formatC(100 * x, format = format, digits = digits, ...), "%")
}

Kullanımla, örneğin,

x <- c(-1, 0, 0.1, 0.555555, 1, 100)
percent(x)

(Tercih ederseniz, biçimini olarak "f"değiştirin "g".)


2
Evet, bu işe yarıyor ve soruda sağladığım geçici çözümün biraz daha genel bir versiyonu. Ama asıl sorum bunun R tabanında var olup olmadığıdır.
Andrie

Yüzdeleri listelemede benim için işe yarıyor, ancak bir istatistiksel veya grafik komutunda "x" i "yüzde (x)" ile değiştirmek bir hata mesajı veriyor.
rolando2

@ rolando2 Hem cevabım hem de krlmlr'nin cevabı, sayılar değil, çıktı olarak karakter vektörlerini döndürür. Eksen etiketlerini ve benzerlerini biçimlendirmek içindir. Belki de sadece 100 ile çarpmak istersiniz?
Richie Cotton

2020 scalesver. 1.1.0 el kitabı şunu söyler: percent()emekli oldu; label_percent()bunun yerine lütfen kullanın , bu sayı biçimlendirmesi için uygun değildir . Böylece elde haddelenmiş çözüm hala geçerli
DzimitryM

74

scalesPaketi kontrol edin . Sanırım bir parçasıydı ggplot2.

library('scales')
percent((1:10) / 100)
#  [1] "1%"  "2%"  "3%"  "4%"  "5%"  "6%"  "7%"  "8%"  "9%"  "10%"

Hassasiyeti tespit etmek için yerleşik mantık, çoğu durumda yeterince iyi çalışmalıdır.

percent((1:10) / 1000)
#  [1] "0.1%" "0.2%" "0.3%" "0.4%" "0.5%" "0.6%" "0.7%" "0.8%" "0.9%" "1.0%"
percent((1:10) / 100000)
#  [1] "0.001%" "0.002%" "0.003%" "0.004%" "0.005%" "0.006%" "0.007%" "0.008%"
#  [9] "0.009%" "0.010%"
percent(sqrt(seq(0, 1, by=0.1)))
#  [1] "0%"   "32%"  "45%"  "55%"  "63%"  "71%"  "77%"  "84%"  "89%"  "95%" 
# [11] "100%"
percent(seq(0, 0.1, by=0.01) ** 2)
#  [1] "0.00%" "0.01%" "0.04%" "0.09%" "0.16%" "0.25%" "0.36%" "0.49%" "0.64%"
# [10] "0.81%" "1.00%"

2
Negatif sayılar için çalışmaz. percent(-0.1)üretirNaN%
akhmed

1
@akhmed: Bu zaten bildirildi, bir düzeltme mevcut ancak incelenmeyi bekliyor: github.com/hadley/scales/issues/50 . Birden fazla negatif sayı için işe yarıyor gibi göründüğünü unutmayın:scales::percent(c(-0.1, -0.2))
krlmlr

Bağlantı için teşekkürler! Bir özellik mi yoksa hata mı olduğundan emin değildim. Birden çok numara için bazen işe yarıyor ve bazen yaramıyor. Söyle, scales::percent(c(-0.1,-0.1,-0.1))üretiyor "NaN%" "NaN%" "NaN%"ama senin örneğin işe yarıyor. Başkalarının referansı için, hata henüz düzeltilmedi scales_0.2.4. Ayrıca, bugün itibariyle, ilgili çekme talebinin sabitlenmesi henüz ana dalda birleştirilmemiştir.
akhmed

34

Paketteki percentişlevi kontrol edin formattable:

library(formattable)
x <- c(0.23, 0.95, 0.3)
percent(x)
[1] 23.00% 95.00% 30.00%

4
+1, bu scales::percent, ilk iki cevapta hangilerinin olmayacağını, kaç hanenin dahil edileceğini belirlemeye izin verir .
Sam Firke

3
+1, kendi işlevinizi döndürmek oldukça kolay olsa da, basamak sayısını seçmenize izin vermek gerçekten yararlıdır.
Gang Su

10

Bu cevaplarda hız için bazı kıyaslamalar yaptım percentvescales yavaşlığı göz önüne alındığında bu kadar lanse pakette . Bunun avantajının, doğru biçimlendirme için otomatik algılayıcısı olduğunu düşünüyorum, ancak verilerinizin neye benzediğini biliyorsanız, kaçınılması gerektiği açıktır.

Yüzde 100.000'lik bir listeyi (0,1) ile 2 basamaklı bir yüzdeyi biçimlendirmeye çalışmanın sonuçları şunlardır:

library(microbenchmark)
x = runif(1e5)
microbenchmark(times = 100L, andrie1(), andrie2(), richie(), krlmlr())
# Unit: milliseconds
#   expr       min        lq      mean    median        uq       max
# 1 andrie1()  91.08811  95.51952  99.54368  97.39548 102.75665 126.54918 #paste(round())
# 2 andrie2()  43.75678  45.56284  49.20919  47.42042  51.23483  69.10444 #sprintf()
# 3  richie()  79.35606  82.30379  87.29905  84.47743  90.38425 112.22889 #paste(formatC())
# 4  krlmlr() 243.19699 267.74435 304.16202 280.28878 311.41978 534.55904 #scales::percent()

Yani sprintfbiz yüzde işareti eklemek istediğinizde bir kesin kazanan. Öte yandan, yalnızca sayıyı çarpıp yuvarlamak istersek ("%" olmadan orantıdan yüzdeye gitmek round()en hızlısıdır:

# Unit: milliseconds
#        expr      min        lq      mean    median        uq       max
# 1 andrie1()  4.43576  4.514349  4.583014  4.547911  4.640199  4.939159 # round()
# 2 andrie2() 42.26545 42.462963 43.229595 42.960719 43.642912 47.344517 # sprintf()
# 3  richie() 64.99420 65.872592 67.480730 66.731730 67.950658 96.722691 # formatC()

8

Scales paketini sadece bu işlem için kullanabilirsiniz (Require veya library ile yüklemeden)

scales::percent(m)

1
Basamak sayısı için doğruluk nasıl verilir?
Elmex80s

6

İşte yeni bir işlevi tanımlamak için benim çözümüm (çoğunlukla Curry ve Compose ile oynayabilmem için :-)):

library(roxygen)
printpct <- Compose(function(x) x*100, Curry(sprintf,fmt="%1.2f%%"))

3

Nasıl scalable::percentdaha yavaş olduğunun gösterildiğini ve Liliana Pacheco'nun başka bir çözüm sunduğunu görünce , devam ettim ve Michael'ın belirlediği örneğe dayanarak onu diğer seçeneklerden bazılarıyla karşılaştırmaya çalıştım:

library(microbenchmark)
library(scales)
library(formattable)

x<-runif(1e5)

lilip <- function() formattable::percent(x,2)
krlmlr <- function() scales::percent(x)
andrie1 <- function() paste0(round(x,4) * 100, '%')

microbenchmark(times=100L,lilip(), krlmlr(), andrie1())

Aldığım sonuçlar şunlar:

Unit: microseconds
      expr        min          lq        mean      median          uq        max neval
   lilip()    194.562    373.7335    772.5663    889.7045    950.4035   1611.537   100
  krlmlr() 226270.845 237985.6560 260194.9269 251581.0235 280704.2320 373022.180   100
 andrie1()  87916.021  90437.4820  92791.8923  92636.8420  94448.7040 102543.252   100

Yine de, neden benim krlmlr()ve neden andrie1()MichaelChirico'nun örneğindekinden daha kötü performans gösterdiğine dair hiçbir fikrim yok . Herhangi bir ipucu?


0
try this~

data_format <- function(data,digit=2,type='%'){
if(type=='d') {
    type = 'f';
    digit = 0;
}
switch(type,
    '%' = {format <- paste("%.", digit, "f%", type, sep='');num <- 100},
    'f' = {format <- paste("%.", digit, type, sep='');num <- 1},
    cat(type, "is not a recognized type\n")
)
sprintf(format, num * data)
}

0

Bu işlev, verileri sütunlara göre yüzdelere dönüştürebilir

percent.colmns = function(base, columnas = 1:ncol(base), filas = 1:nrow(base)){
    base2 = base
    for(j in columnas){
        suma.c = sum(base[,j])
        for(i in filas){
            base2[i,j] = base[i,j]*100/suma.c
        }
    }
    return(base2)
}

Temel aritmetik vektörleştirilmiştir - iç döngü verimsizdir ve gereksizdir. İle değiştirilebilir base2[, j] = base[ , j] * 100 / suma.c. Ayrıca bunun soruya tam olarak bir cevap olmadığını da belirtmekte fayda var ... soru 0.5"% 50.0" gibi bir şey biçimlendirmekle ilgili, hesaplama yapmakla ilgili değil ...
Gregor Thomas

0

tidyverseVersiyon şudur:

> library(tidyverse)

> set.seed(1)
> m <- runif(5)
> dt <- as.data.frame(m)

> dt %>% mutate(perc=scales::percent(m,accuracy=0.001))
          m    perc
1 0.2655087 26.551%
2 0.3721239 37.212%
3 0.5728534 57.285%
4 0.9082078 90.821%
5 0.2016819 20.168%

Her zamanki gibi düzenli görünüyor.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.