使用正则表达式将一列拆分为两列
Split a Column Into 2 Using Regular Expression
我有一个包含以下格式的时间的数据框:
df<-data.frame(time=c("1655","1055","1123","1505"))
# time
# 1 1655
# 2 1055
# 3 1123
# 4 925
我想将其更改为标准格式,即带冒号的 16:55:00,但是使用 lubridate
包中的函数 hms
将不起作用。
我正在考虑将 time
列分成 2 列,这样我就可以:
# time1 time2
# 1 16 55
# 2 10 55
# 3 11 23
# 4 9 25
然后使用 :
作为分隔符将它们组合回去:
# time
# 1 16:55
# 2 10:55
# 3 11:23
# 4 09:25
但是,我不确定该怎么做(尤其是处理正则表达式)。我试过了:
library(tidyr)
df %>%
separate(time,c("time1","time2"),sep="[[:digit:]$]{2}") %>%
unite(time,time1,time,sep=":")
当然,这不行。
我们可以使用sprintf
将3位数字转换为4位数字,方法是在开头附加0,然后使用sub
,我们匹配开头的两个字符并捕获为一组( (.{2})
) 并将其替换为后跟 :
.
的反向引用 (\1
)
df$time <- sub("^(.{2})", "\1:", sprintf("%04d", as.integer(as.character(df$time))))
df$time
#[1] "16:55" "10:55" "11:23" "09:25"
或者另一个选项是 str_pad
来自 stringr
library(stringr)
sub("(.{2})$", ":\1", str_pad(df$time, 4, "left", pad = "0"))
#[1] "16:55" "10:55" "11:23" "09:25"
如果我们更喜欢 tidyverse
,那么 separate/unite
也可以,如果我们先 mutate
和 sprintf
library(tidyverse)
df %>%
mutate(time = sprintf("%04d", as.integer(as.character(time)))) %>%
separate(time, into = c("time1", "time2"), sep=2) %>%
unite(time, time1, time2, sep=":")
# time
#1 16:55
#2 10:55
#3 11:23
#4 09:25
或 str_pad/str_replace
来自 stringr
df %>%
mutate(time = str_pad(time, 4, "left", pad = "0"),
time = str_replace(time, "(.{2})", "\1:"))
# time
#1 16:55
#2 10:55
#3 11:23
#4 09:25
数据
df <- data.frame(time=c("1655","1055","1123","925"))
注意:在不使用 stringsAsFactors
的情况下创建 data.frame
将默认使用 stringsAsFactors=TRUE
,因此带有 factor
的列将转换为 integer
as.integer(as.character
用作 sprintf
的输入
如果你确实想使用 lubridate
将时间存储为 Period
你可以使用类似下面的东西
df<-data.frame(time=c("1655","1055","1123","1505","955"))
df$time2 <- hm(gsub("(.{2}$)",":\1",df$time))
gsub
在最后两个字符前插入一个“:”
hm
从 lubridate
将其转换为 Period
对象。
我有一个包含以下格式的时间的数据框:
df<-data.frame(time=c("1655","1055","1123","1505"))
# time
# 1 1655
# 2 1055
# 3 1123
# 4 925
我想将其更改为标准格式,即带冒号的 16:55:00,但是使用 lubridate
包中的函数 hms
将不起作用。
我正在考虑将 time
列分成 2 列,这样我就可以:
# time1 time2
# 1 16 55
# 2 10 55
# 3 11 23
# 4 9 25
然后使用 :
作为分隔符将它们组合回去:
# time
# 1 16:55
# 2 10:55
# 3 11:23
# 4 09:25
但是,我不确定该怎么做(尤其是处理正则表达式)。我试过了:
library(tidyr)
df %>%
separate(time,c("time1","time2"),sep="[[:digit:]$]{2}") %>%
unite(time,time1,time,sep=":")
当然,这不行。
我们可以使用sprintf
将3位数字转换为4位数字,方法是在开头附加0,然后使用sub
,我们匹配开头的两个字符并捕获为一组( (.{2})
) 并将其替换为后跟 :
.
\1
)
df$time <- sub("^(.{2})", "\1:", sprintf("%04d", as.integer(as.character(df$time))))
df$time
#[1] "16:55" "10:55" "11:23" "09:25"
或者另一个选项是 str_pad
来自 stringr
library(stringr)
sub("(.{2})$", ":\1", str_pad(df$time, 4, "left", pad = "0"))
#[1] "16:55" "10:55" "11:23" "09:25"
如果我们更喜欢 tidyverse
,那么 separate/unite
也可以,如果我们先 mutate
和 sprintf
library(tidyverse)
df %>%
mutate(time = sprintf("%04d", as.integer(as.character(time)))) %>%
separate(time, into = c("time1", "time2"), sep=2) %>%
unite(time, time1, time2, sep=":")
# time
#1 16:55
#2 10:55
#3 11:23
#4 09:25
或 str_pad/str_replace
来自 stringr
df %>%
mutate(time = str_pad(time, 4, "left", pad = "0"),
time = str_replace(time, "(.{2})", "\1:"))
# time
#1 16:55
#2 10:55
#3 11:23
#4 09:25
数据
df <- data.frame(time=c("1655","1055","1123","925"))
注意:在不使用 stringsAsFactors
的情况下创建 data.frame
将默认使用 stringsAsFactors=TRUE
,因此带有 factor
的列将转换为 integer
as.integer(as.character
用作 sprintf
如果你确实想使用 lubridate
将时间存储为 Period
你可以使用类似下面的东西
df<-data.frame(time=c("1655","1055","1123","1505","955"))
df$time2 <- hm(gsub("(.{2}$)",":\1",df$time))
gsub
在最后两个字符前插入一个“:”
hm
从 lubridate
将其转换为 Period
对象。