2013-01-18 35 views
17

Tôi đang xử lý một DB với định dạng giờ như:Pad với số không dẫn đến độ rộng phổ biến

HOUR ID 
1 2 
10 4 
5 6 
20 6 

Tôi muốn đặt một số không tính vào giá trị với 1 ký tự và lưu trữ chúng trong một cột mới có tên NHOUR, như:

NHOUR HOUR ID 
01 1 2 
10 10 4 
05 5 6 
20 20 6 

cho đến bây giờ tôi đang phải vật lộn với một cái gì đó tương tự (tôi làm theo một số gợi ý đã được cung cấp cho ifelse trong diễn đàn):

DB$NHOUR<-with(DB,ifelse(nchar(HOUR,type="chars")==1),sprintf("%02d",HOUR),as.numeric(HOUR)) 

nhưng không thành công! R luôn báo cáo phần tử "có" không được chỉ định, v.v.

Như mọi khi, mọi lời khuyên đều được đánh giá cao!

+5

Điều này có vẻ như bạn đang làm mọi thứ, quá phức tạp. Tại sao không chỉ 'sprintf ("% 02d ", DB $ HOUR)'? Toàn bộ điểm của hàm đó là nó có các số 0 đứng đầu với chiều dài là 2 ký tự. – joran

+0

'sprintf' và' as.numeric' không nằm trong cuộc gọi 'ifelse' khi chúng cần; có một dấu ngoặc đơn đóng trước chúng. Ngoài ra, bạn đang trộn các loại trả về bên trong 'ifelse' sẽ dẫn đến loại quảng cáo mà bạn có thể không mong đợi. –

+5

Cuối cùng, vì bạn tương đối mới ở đây và đã hỏi một số câu hỏi, tôi nghĩ sẽ hữu ích khi chỉ ra rằng khi câu trả lời giải quyết được vấn đề của bạn, rất hữu ích khi nhấp vào dấu kiểm bên cạnh. Điều này giúp cải thiện đáng kể giá trị của câu hỏi (và trang web) bằng cách đưa ra một dấu hiệu rõ ràng cho người dùng trong tương lai khi câu trả lời đã giải quyết được vấn đề của bạn. Tuy nhiên, hãy nhớ rằng bạn không bắt buộc phải chấp nhận câu trả lời; nó được đánh giá cao, nhưng nó luôn là lựa chọn của bạn. – joran

Trả lời

37

Đơn giản chỉ cần làm theo lời khuyên trong bình luận @ Joran của,

DB <- data.frame(
HOUR = c(1, 10, 5, 20), 
ID = c(2, 4, 6, 6)) 

NHOUR <- sprintf("%02d",DB$HOUR) # fix to 2 characters 

cbind(NHOUR, DB) # combine old and newdata 
    NHOUR HOUR ID 
1 01 1 2 
2 10 10 4 
3 05 5 6 
4 20 20 6 

Cập nhật 2013/01/21 23: 42: 00Z Lấy cảm hứng từ daroczig's performance test below, và vì tôi muốn thử microbenchmark package, tôi đã cập nhật câu hỏi này với một thử nghiệm hiệu suất nhỏ của riêng tôi so sánh ba giải pháp khác nhau được đề xuất trong chủ đề này.

# install.packages(c("microbenchmark", "stringr"), dependencies = TRUE) 
require(microbenchmark) 
require(stringr) 

SPRINTF <- function(x) sprintf("%02d", x) 
FORMATC <- function(x) formatC(x, width = 2,flag = 0) 
STR_PAD <- function(x) str_pad(x, width=2, side="left", pad="0") 

x <- round(runif(1e5)*10) 
res <- microbenchmark(SPRINTF(x), STR_PAD(x), FORMATC(x), times = 15) 

## Print results: 
print(res) 
Unit: milliseconds 
     expr  min  lq median  uq  max 
1 FORMATC(x) 623.53785 629.69005 638.78667 671.22769 679.8790 
2 SPRINTF(x) 34.35783 34.81807 35.04618 35.53696 37.1622 
3 STR_PAD(x) 116.54969 118.41944 118.97363 120.05729 163.9664 

### Plot results: 
boxplot(res) 

Box Plot of microbenchmark results

+0

Một lần nữa, tôi làm phức tạp công việc ... Tôi nghĩ rằng sprintf sẽ đặt một số không trước bất kỳ giá trị nào!Rất cám ơn Joran, cũng vì làm rõ trong những sai lầm ifelse và cảm ơn Eric để báo cáo rõ ràng mã! – stefano

4

giải pháp thay thế:

> formatC(DB$HOUR, width = 2,flag = 0) 
[1] "01" "10" "05" "20" 

Cập nhật: Tôi vừa mới chạy một thử nghiệm nhanh về vấn đề hiệu suất chỉ để ghi lại câu hỏi này

> library(microbenchmark) 
> SPRINTF <- function(x) sprintf("%02d", x) 
> FORMATC <- function(x) formatC(x, width = 2,flag = 0) 
> x <- round(runif(1e5)*10) 
> microbenchmark(SPRINTF(x), FORMATC(x), times = 10) 
Unit: milliseconds 
     expr  min  lq median  uq  max 
1 FORMATC(x) 688.35430 723.42458 767.06025 780.84768 878.4966 
2 SPRINTF(x) 31.29167 31.96052 35.75735 40.54656 147.6805 
+3

+1 điều này rõ ràng hơn nhiều so với sử dụng 'sprintf'. tại sao sử dụng cú pháp cũ với ngôn ngữ hiện đại? –

+1

@MatthewPlourde, bạn có muốn mở rộng quan điểm của mình không? Bạn có ý gì bởi _much clearer_? Trong so sánh nhanh chóng của tôi về 'sprintf' và 'formatC', cái đầu tiên xuất hiện nhanh hơn nhiều, nhưng tất nhiên tốc độ không phải là tất cả. –

+0

@EricFail no kidding! sự khác biệt về tốc độ lớn hơn rất nhiều so với tôi đoán. Sự nhiệt tình của tôi đối với 'formatC' đã được làm nóng. Nếu tốc độ không phải là một mối quan tâm, mặc dù, tôi thích nó. Nhiều người làm việc với R không đến từ một nền tảng lập trình. Tôi luôn ủng hộ cách tiếp cận với khả năng đọc cao nhất từ ​​góc nhìn của noob. nhưng bạn cũng có một cuộc bỏ phiếu, bởi vì đó là đêm thứ Sáu. –

9

Tôi thích sử dụng các stringr gói:

DB$NHOUR <- str_pad(DB$HOUR, width=2, side="left", pad="0") 
+0

Bạn có thể giải thích lý do tại sao bạn thích gói stringr? –

+3

Eric, nó thích nó để dễ đọc. Khi ai đó đang đọc mã của bạn và họ thấy 'gsub' hoặc, trong trường hợp này, 'sprintf' nó không thực sự rõ ràng những gì đang xảy ra. Nhưng các hàm 'stringr' rất dễ đọc. Ví dụ: 'str_replace_all',' string_detect' hoặc 'str_pad', rất dễ hiểu các hoạt động đang được hoàn thiện. – rrs

+0

Cảm ơn bạn đã trả lời câu hỏi của tôi, tôi luôn tò mò tìm hiểu những điều mới. Có lẽ bởi vì tôi đến từ một nền khoa học phi máy tính và do đó tôi không hiểu tại sao một số mã có khả năng đọc cao hơn thì khác. Đối với tôi, các phần tử từ gói cơ sở thường có nhiều hơn _readable_. Hơn nữa, tôi đã thực hiện một thử nghiệm tốc độ nhỏ (sử dụng 'proc.time()') và trên máy tính của tôi 'sprintf' xuất hiện nhanh gấp hai lần' str_pad', nhưng tốc độ lại không phải là tất cả. –

1

Tương tự như các stringr, có stri_pad_left từ stringi

library(stringi) 
stri_pad_left(str=DB$HOUR, 2, pad="0") 
# [1] "01" "10" "05" "20" 

Nó nên được khá nhiều việc cùng tốc độ khôn ngoan. Có các chức năng đệm tương tự cho bên phải và cả hai bên.

Các vấn đề liên quan