【问题标题】:Pad with leading zeros to common width [duplicate]用前导零填充到公共宽度[重复]
【发布时间】:2013-01-02 18:18:56
【问题描述】:

我正在处理一个小时格式的数据库,例如:

HOUR ID
1  2
10 4
5  6
20 6

我想用 1 个字符在值中放置一个零,并将它们存储在一个名为 NHOUR 的新列中,例如:

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

直到现在我都在努力解决类似的问题(我遵循论坛中已经为 ifelse 提供的一些建议):

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

但没有任何成功! R 总是报告“是”元素未指定,等等。

一如既往,感谢任何提示!

【问题讨论】:

  • 这看起来你在做事,太复杂了。为什么不只是sprintf("%02d",DB$HOUR)?该函数的重点是它用前导零填充到 2 个字符的长度。
  • sprintfas.numeric 不在 ifelse 调用中,因为它们需要在;它们前面有一个右括号。此外,您在 ifelse 中混合了返回类型,这将导致您可能没有预料到的类型提升。
  • 最后,由于您在这里相对较新并且已经提出了一些问题,我认为指出当答案解决您的问题时,单击检查会很有帮助标记旁边。通过向未来的用户明确指出哪个答案解决了您的问题,这极大地提高了问题(和站点)的价值。但是,请始终记住,您没有义务接受答案;我们很感激,但它始终是您的选择。

标签: r


【解决方案1】:

只需遵循@joran 评论中的建议,

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

2013-01-21 23:42:00Z 更新daroczig's performance test below 的启发,因为我想尝试microbenchmark package,所以我用一个小的性能测试更新了这个问题我自己比较了这个帖子中建议的三种不同的解决方案。

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

【讨论】:

  • 再一次,我使工作复杂化了......我认为 sprintf 会在任何值前面加上一个零!非常感谢 Joran,也感谢对 ifelse 错误的澄清,感谢 Eric 清楚地报告代码!
【解决方案2】:

替代解决方案:

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

更新:我刚刚对性能问题进行了快速测试,只是为了记录这个问题

> 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

【讨论】:

  • +1 这比使用sprintf 清楚得多。为什么要在现代语言中使用旧语法?
  • @MatthewPlourde,您愿意扩展您的观点吗?你说的更清晰是什么意思?在我对sprintfformatC 的快速比较中,前者的速度要快得多,但当然速度并不是一切。
  • @EricFail 不开玩笑!速度上的差异比我想象的要大得多。我对formatC 的热情已经消退。不过,如果速度不是问题,我更喜欢它。许多使用 R 的人都没有编程背景。从菜鸟的角度来看,我总是喜欢可读性最高的方法。但你也投了赞成票,因为现在是星期五晚上。
  • @daroczig,我喜欢你添加了性能测试,干得好。
【解决方案3】:

我喜欢使用stringr 包:

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

【讨论】:

  • 你能详细说明你为什么喜欢 stringr 包吗?
  • Eric,它喜欢它的可读性。当其他人正在阅读您的代码并且他们看到 gsub 或者在这种情况下为 sprintf 时,并不清楚发生了什么。但是stringr 函数可读性很强。例如,str_replace_allstring_detectstr_pad,很容易理解正在执行的操作。
  • 感谢您回答我的问题,我总是对学习新事物充满好奇。也许是因为我来自非计算机科学背景,因此我不明白为什么有些代码比其他代码具有更高的可读性。对我来说,基本包中的元素通常更可读。此外,我做了一个小速度测试(使用proc.time()),在我的机器上sprintf 的速度几乎是str_pad 的两倍,但速度又不是一切。
  • @rrs , @eric 请小心使用 'str_pad' 函数,因为它不会在格式化之前将数字转换为字符(用 0 填充)。所以如果你有一个像x=600000 这样的实例并使用str_pad(x, width = 7, pad = "0"),你的输出将是“006e+05”而不是“0600000”。
  • 好点。你知道一个好的选择吗?
【解决方案4】:

类似于stringr,还有stri_pad_left来自stringi

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

在速度方面应该几乎相同。右侧和两侧都有类似的填充功能。

【讨论】:

    猜你喜欢
    • 2011-03-28
    • 2012-04-21
    • 2015-05-21
    • 2014-09-19
    • 2011-10-09
    • 2013-02-07
    • 2021-12-18
    • 1970-01-01
    • 2010-11-19
    相关资源
    最近更新 更多