Làm thế nào để định dạng một số là phần trăm trong R?


135

Một trong những điều từng làm tôi bối rối khi là người mới của R là cách định dạng số theo tỷ lệ phần trăm để in.

Ví dụ, hiển thị 0.12345dưới dạng 12.345%. Tôi có một số cách giải quyết cho việc này, nhưng không ai trong số này có vẻ là "người mới thân thiện". Ví dụ:

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

Câu hỏi: Có chức năng cơ sở R để làm việc này không? Ngoài ra, có một gói được sử dụng rộng rãi cung cấp một trình bao bọc thuận tiện?


Mặc dù tìm kiếm một cái gì đó như thế này ?format, ?formatC?prettyNum, tôi vẫn chưa tìm thấy một trình bao bọc thuận tiện phù hợp trong cơ sở R. ??"percent"không mang lại bất cứ điều gì hữu ích. library(sos); findFn("format percent")trả về 1250 lượt truy cập - vì vậy một lần nữa không hữu ích. ggplot2có chức năng percentnhưng điều này không kiểm soát độ chính xác làm tròn.


5
sprintfdường như là giải pháp yêu thích trong danh sách gửi thư và tôi chưa thấy giải pháp nào tốt hơn. Bất kỳ chức năng tích hợp nào sẽ không đơn giản hơn nhiều để gọi, phải không?
michel-slm

1
Theo quan điểm của tôi sprintflà hoàn toàn tốt cho tập hợp con của các lập trình viên R cũng là lập trình viên. Tôi đã mã hóa rất nhiều trong cuộc sống của mình, bao gồm cả COBOL (shudder) và fortran (cho thấy tuổi của tôi). Nhưng tôi không xem xét các sprintfquy tắc định dạng rõ ràng (bản dịch: WTF?). Và tất nhiên, một trình bao bọc chuyên dụng phải dễ gọi hơn sprintf, ví dụ:format_percent(x=0.12345, digits=2)
Andrie

@hircus Tôi nghĩ rằng nó đủ phổ biến để nó xứng đáng với chức năng cuộn ngắn của chính nó. Đó là một vấn đề đặc biệt với Sweave, trong đó \ Sexpr {sprintf (% 1.2f %% ", myvar)} xấu hơn nhiều so với \ Sexpr {pct (myvar)} hoặc bất cứ chức năng ngắn nào sẽ là.
Ari B. Friedman

2
Không học cách sử dụng các công cụ thích hợp mà chúng ta mong đợi người dùng sẽ hướng tới? Ý tôi là, học cách sử dụng sprintf()hầu như không tốn nhiều thời gian hơn là tìm ra gói foo chứa format_percent(). Điều gì xảy ra nếu người dùng sau đó không muốn định dạng theo phần trăm nhưng một cái gì đó tương tự? Họ cần tìm một bọc khác. Về lâu dài việc học các công cụ cơ bản sẽ có lợi.
Gavin Simpson

1
Có một vấn đề nhỏ ở đây %là ký tự nhận xét trong LaTeX, đó là định dạng báo cáo "mặc định" cho R. Vì vậy, trong khi nó có thể hữu ích cho việc ghi nhãn biểu đồ, thì phải cẩn thận nếu số được định dạng bị xóa.
James

Câu trả lời:


118

Thậm chí sau này:

Như @DzimitryM đã chỉ ra, percent()đã được "nghỉ hưu" theo hướng có lợi label_percent(), đó là một từ đồng nghĩa với percent_format()chức năng cũ .

label_percent() trả về một hàm, vì vậy để sử dụng nó, bạn cần thêm một cặp dấu ngoặc đơn.

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

Tùy chỉnh điều này bằng cách thêm các đối số bên trong bộ dấu ngoặc đơn đầu tiên.

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

Một bản cập nhật, vài năm sau:

Ngày nay, có một percentchức năng trong scalesgói, như được ghi trong câu trả lời của krlmlr. Sử dụng thay vì giải pháp cuộn tay của tôi.


Hãy thử một cái gì đó như

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

Với việc sử dụng, ví dụ,

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

(Nếu bạn thích, hãy thay đổi định dạng từ "f"thành "g".)


2
Vâng, điều này hoạt động, và là một phiên bản chung hơn một chút của cách giải quyết tôi cung cấp trong câu hỏi. Nhưng câu hỏi thực sự của tôi là liệu điều này có tồn tại trong cơ sở R hay không.
Andrie

Hoạt động với tôi trong việc liệt kê phần trăm, nhưng thay thế "x" bằng "phần trăm (x)" trong lệnh thống kê hoặc biểu đồ sẽ tạo ra một thông báo lỗi.
rolando2

@ rolando2 Cả vectơ câu trả lời của tôi và câu trả lời của krlmlr đều trả về các vectơ ký tự là đầu ra, không phải số. Chúng là để định dạng nhãn trục và tương tự. Có lẽ bạn chỉ muốn nhân với 100?
Richie Cotton

Tính đến năm 2020 scalesver. Hướng dẫn 1.1.0 cho biết: percent()đã nghỉ hưu; vui lòng sử dụng label_percent()thay thế, không phù hợp với định dạng số . Vì vậy, giải pháp cuộn tay vẫn có liên quan
DzimitryM

74

Kiểm tra các scalesgói. Nó từng là một phần của ggplot2, tôi nghĩ vậy.

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

Logic tích hợp để phát hiện độ chính xác sẽ hoạt động đủ tốt cho hầu hết các trường hợp.

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
Không hoạt động cho số âm. percent(-0.1)sản xuấtNaN%
akhmed

1
@akhmed: Điều này đã được báo cáo rồi, đã có bản sửa lỗi nhưng đang chờ xem xét: github.com/hadley/scales/issues/50 . Lưu ý rằng nó dường như hoạt động với nhiều hơn một số âm:scales::percent(c(-0.1, -0.2))
krlmlr

Cảm ơn các liên kết! Tôi không chắc đó là một tính năng hay một lỗi. Đối với nhiều số, đôi khi nó hoạt động và đôi khi không. Nói, scales::percent(c(-0.1,-0.1,-0.1))sản xuất "NaN%" "NaN%" "NaN%"nhưng ví dụ của bạn không hoạt động. Đối với tham chiếu của người khác, lỗi chưa được sửa chữa scales_0.2.4. Ngoài ra, cho đến ngày hôm nay, yêu cầu kéo tương ứng sửa nó vẫn chưa được sáp nhập vào nhánh chính.
akhmed

34

Kiểm tra percentchức năng từ formattablegói:

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

4
+1, điều này cho phép chỉ định có bao nhiêu chữ số, scales::percenttrong hai câu trả lời đầu tiên thì không.
Sam Firke

3
+1, mặc dù việc cuộn chức năng của bạn khá dễ dàng, cho phép chọn số chữ số thực sự hữu ích.
Gang Su

10

Tôi đã thực hiện một số điểm chuẩn cho tốc độ của những câu trả lời này và rất ngạc nhiên khi thấy percenttrong scalesgói được chào hàng, vì sự chậm chạp của nó. Tôi tưởng tượng lợi thế là trình phát hiện tự động của nó để định dạng chính xác, nhưng nếu bạn biết dữ liệu của bạn trông như thế nào thì có vẻ tránh được.

Dưới đây là kết quả từ việc cố gắng định dạng danh sách 100.000 phần trăm trong (0,1) đến tỷ lệ phần trăm trong 2 chữ số:

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()

Vì vậy, sprintfnổi lên như một người chiến thắng rõ ràng khi chúng tôi muốn thêm một dấu phần trăm. Mặt khác, nếu chúng ta chỉ muốn nhân số và làm tròn (đi từ tỷ lệ thành phần trăm mà không có "%", thì round()nhanh nhất:

# 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

Bạn có thể sử dụng gói quy mô chỉ cho thao tác này (không tải nó với yêu cầu hoặc thư viện)

scales::percent(m)

1
Làm thế nào để đưa ra độ chính xác cho số chữ số?
Elmex80s

6

Đây là giải pháp của tôi để xác định chức năng mới (chủ yếu để tôi có thể chơi xung quanh với Curry và Compose :-)):

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

3

Xem làm thế nào scalable::percentđã được chứng minh là chậm nhất và Liliana Pacheco đưa ra một giải pháp khác, tôi đã tiếp tục và cố gắng đánh giá nó theo một số tùy chọn khác dựa trên ví dụ Michael đặt ra:

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())

Đây là những kết quả tôi nhận được:

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

Mặc dù vậy, tôi không biết tại sao krlmlr()và tại sao tôi lại andrie1()biểu diễn tệ hơn nhiều so với ví dụ của MichaelChirico. Bất kì manh mối nào?


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

Hàm này có thể chuyển đổi dữ liệu thành tỷ lệ phần trăm theo cột

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)
}

Số học cơ bản được vector hóa --- vòng lặp for bên trong là không hiệu quả và không cần thiết. Có thể thay thế bằng base2[, j] = base[ , j] * 100 / suma.c. Cũng đáng lưu ý rằng đây không chính xác là một câu trả lời cho câu hỏi ... câu hỏi là về định dạng giống như 0.5"50,0%", chứ không phải về việc tính toán ...
Gregor Thomas

0

Các tidyversephiên bản này:

> 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%

Trông gọn gàng như thường lệ.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.