通过连接非均匀长度的子串来创建数据框
Creating a dataframe by concatenating substrings of non-uniform lengths
原始数据 (.txt) 文件有 65926 个元素,每个包含 142 个字符串。
这是原始数据文件的dropbox link。
任务是将这 142 个字符串分成 37 个更小的字符串(每个子字符串是一个单独的字符变量),每个字符串依次从以下位置开始:
1,4,9,11,14,15,16,19,21,24,26,27,28,32,33,34,36,38,43,45,46,47,48,52,56, 60,66,72,75,76,77,78,79,80,127,130,133
最终输出必须是 65926 x 37 数据帧。这是输出数据帧的快照:
这是我使用的代码:
x <- readLines("R71252L01.TXT")
a <- c(1,4,9,11,14,15,16,19,21,24,26,27,28,32,33,34,36,38,43,45,46,47,48,52,56,60,66,72,75,76,77,78,79,80,127,130,133)
z <- data.frame(matrix(nrow = length(x), ncol = length(a)), stringsAsFactors = FALSE)
for (i in 1:length(x) ) {
z[i,] <- (list(
(c(substr(x[i], 1, 3),substr(x[i], 4, 8),substr(x[i], 9, 10),
substr(x[i], 11, 13),substr(x[i], 14, 14),substr(x[i], 15, 15),
substr(x[i], 16, 18),substr(x[i], 19, 20),substr(x[i], 21, 23),
substr(x[i], 24, 25),substr(x[i], 26, 26),substr(x[i], 27, 27),
substr(x[i], 28, 31),substr(x[i], 32, 32),substr(x[i], 33, 33),
substr(x[i], 34, 35),substr(x[i], 36, 37),substr(x[i], 38, 42),
substr(x[i], 43, 44),substr(x[i], 45, 45),substr(x[i], 46, 46),
substr(x[i], 47, 47),substr(x[i], 48, 51),substr(x[i], 52, 55),
substr(x[i], 56, 56),substr(x[i], 60, 65),substr(x[i], 66, 71),
substr(x[i], 72, 74),substr(x[i], 75, 75),substr(x[i], 76, 76),
substr(x[i], 77, 77),substr(x[i], 78, 78),substr(x[i], 79, 79),
substr(x[i], 80, 126),substr(x[i], 127, 129),substr(x[i], 130, 132),
substr(x[i], 133, 142)
) )
) )
i <- i+1
}
代码有效,但有两个问题:
substr()
的开始和停止索引必须手动输入。有什么方法可以利用向量 a
而不是所有的体力劳动?
代码执行需要 30 多分钟。检查时间:
> system.time(source('Hitesh_Script.R'))
user system elapsed
4452.464 9.440 4476.018
这可以做得更快吗?
我必须对多个原始数据文件执行此任务,每个文件具有不同的矢量 a
。因此,任何其他关于效率的建议也将受到赞赏。非常感谢!
刚刚模拟了一个scratch数据,分享了一个简单的代码
a <- c(1,4,9,11,14,15,16,19,21,24,26,27,28,32,33,34,36,38,43,45,46,47,48,52,
56,60,66,72,75,76,77,78,79,80,127,130,133)
df = data.frame(
x = c("uiagdsjgcjkh bijacydgasxdhsfkajdh,cnfwkeyrg,urnyhvguirwljbhgkjgjgdkgkdgkgdkgdkgdkgdkgdkgdkgdkdgkdgkdgkdgkjdgkdwjbiuayeiuy ke,ynh lgdiyl",
"kjhfkjsdlfkojjhgckjasnhjhckjsybsanhdsabtgchbtsjahasijhcndkuysefiuwyhsnidxjnkausetfba jwf,mycaiusftbbawubbctejdgkjdghjgdduiacwyftacbm"))
# > df
# x
# 1 uiagdsjgcjkh bijacydgasxdhsfkajdh,cnfwkeyrg,urnyhvguirwljbhgkjgjgdkgkdgkgdkgdkgdkgdkgdkgdkgdkdgkdgkdgkdgkjdgkdwjbiuayeiuy ke,ynh lgdiyl
# 2 kjhfkjsdlfkojjhgckjasnhjhckjsybsanhdsabtgchbtsjahasijhcndkuysefiuwyhsnidxjnkausetfba jwf,mycaiusftbbawubbctejdgkjdghjgdduiacwyftacbm
df1 <- data.frame(lapply(df, function(x) lapply(seq_along(a), function(i){
if (i==length(a))
substr(x,a[i],nchar(as.character(x)))
else
substr(x,a[i],a[i+1]-1)}
)))
colnames(df1)=paste0("x",1:dim(df1)[2])
df1
# x1 x2 x3 x4 x5 x6 x7 x8 x9 x10 x11 x12 x13 x14 x15 x16 x17 x18 x19 x20 x21
# 1 uia gdsjg cj kh b i jac yd gas xd h s fkaj d h ,c nf wkeyr g, u r
# 2 kjh fkjsd lf koj j h gck ja snh jh c k jsyb s a nh ds abtgc hb t s
# x22 x23 x24 x25 x26 x27 x28 x29 x30 x31 x32 x33
# 1 n yhvg uirw ljbh gkjgjg dkgkdg kgd k g d k g
# 2 j ahas ijhc ndku ysefiu wyhsni dxj n k a u s
# x34 x35 x36 x37
# 1 dkgdkgdkgdkgdkdgkdgkdgkdgkjdgkdwjbiuayeiuy ke,y nh lgd iyl
# 2 etfba jwf,mycaiusftbbawubbctejdgkjdghjgdduiacwy fta cbm
似乎 readr
包(Hadley 的 tidyverse 的一部分)提供了一种更快的解决方案来一次性读取和拆分固定宽度的文件。
Dropbox 上给定的样本文件在我的系统上花费了 0.17 秒的时间 来读入并且 return 65,926 × 37 data.frame.
library(readr)
a <- c(1,4,9,11,14,15,16,19,21,24,26,27,28,32,33,34,36,38,43,45,46,47,48,52,56,60,66,72,
75,76,77,78,79,80,127,130,133)
z <- read_fwf("R71252L01.TXT", fwf_widths(diff(c(a, 142))),
col_types = stringr::str_dup("c", length(a)))
输出是一个 tibble,一个改进的 data.frame
:
print(z, n = 3, width = Inf)
# A tibble: 65,926 × 37
X1 X2 X3 X4 X5 X6 X7 X8 X9 X10
<chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
1 000 37773 71 252 1 1 012 05 005 01
2 000 37773 71 252 1 1 012 05 005 01
3 000 37773 71 252 1 1 012 05 005 01
X11 X12 X13 X14 X15 X16 X17 X18 X19 X20
<chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
1 1 2 0110 1 2 01 01 00000 01 1
2 1 2 0110 1 2 02 01 00000 01 1
3 1 2 0110 1 2 03 01 00000 01 1
X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
<chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
1 1 <NA> 6538 4001 <NA> 120314 310314 115 2 2
2 1 <NA> 6538 4001 <NA> 120314 310314 90 2 2
3 1 <NA> 6538 4001 <NA> 130314 310314 90 2 2
X31 X32 X33 X34 X35 X36 X37
<chr> <chr> <chr> <chr> <chr> <chr> <chr>
1 2 2 2 <NA> 1 2 21433
2 2 2 2 <NA> 1 2 21433
3 2 2 2 <NA> 1 2 21433
解释
您可以指定字段宽度或字段的开始和结束位置。使用 diff
从给定的起始位置 a
计算宽度需要较少的编码。但是,必须以任何方式指定结束位置 (142)。
为了与 Q 保持一致,我强制所有列的类型为 character
,参数为 col_types = stringr::str_dup("c", length(a))
。如果 OP 需要列为其他类型,可以根据需要指定或依赖内置类型识别,请参见 help("read_fwf")
。
我也先尝试了 read.fwf()
,但这是 数量级的慢 (耗时 32.7 秒)。
原始数据 (.txt) 文件有 65926 个元素,每个包含 142 个字符串。
这是原始数据文件的dropbox link。
任务是将这 142 个字符串分成 37 个更小的字符串(每个子字符串是一个单独的字符变量),每个字符串依次从以下位置开始: 1,4,9,11,14,15,16,19,21,24,26,27,28,32,33,34,36,38,43,45,46,47,48,52,56, 60,66,72,75,76,77,78,79,80,127,130,133
最终输出必须是 65926 x 37 数据帧。这是输出数据帧的快照:
这是我使用的代码:
x <- readLines("R71252L01.TXT")
a <- c(1,4,9,11,14,15,16,19,21,24,26,27,28,32,33,34,36,38,43,45,46,47,48,52,56,60,66,72,75,76,77,78,79,80,127,130,133)
z <- data.frame(matrix(nrow = length(x), ncol = length(a)), stringsAsFactors = FALSE)
for (i in 1:length(x) ) {
z[i,] <- (list(
(c(substr(x[i], 1, 3),substr(x[i], 4, 8),substr(x[i], 9, 10),
substr(x[i], 11, 13),substr(x[i], 14, 14),substr(x[i], 15, 15),
substr(x[i], 16, 18),substr(x[i], 19, 20),substr(x[i], 21, 23),
substr(x[i], 24, 25),substr(x[i], 26, 26),substr(x[i], 27, 27),
substr(x[i], 28, 31),substr(x[i], 32, 32),substr(x[i], 33, 33),
substr(x[i], 34, 35),substr(x[i], 36, 37),substr(x[i], 38, 42),
substr(x[i], 43, 44),substr(x[i], 45, 45),substr(x[i], 46, 46),
substr(x[i], 47, 47),substr(x[i], 48, 51),substr(x[i], 52, 55),
substr(x[i], 56, 56),substr(x[i], 60, 65),substr(x[i], 66, 71),
substr(x[i], 72, 74),substr(x[i], 75, 75),substr(x[i], 76, 76),
substr(x[i], 77, 77),substr(x[i], 78, 78),substr(x[i], 79, 79),
substr(x[i], 80, 126),substr(x[i], 127, 129),substr(x[i], 130, 132),
substr(x[i], 133, 142)
) )
) )
i <- i+1
}
代码有效,但有两个问题:
substr()
的开始和停止索引必须手动输入。有什么方法可以利用向量a
而不是所有的体力劳动?代码执行需要 30 多分钟。检查时间:
> system.time(source('Hitesh_Script.R')) user system elapsed 4452.464 9.440 4476.018
这可以做得更快吗?
我必须对多个原始数据文件执行此任务,每个文件具有不同的矢量 a
。因此,任何其他关于效率的建议也将受到赞赏。非常感谢!
刚刚模拟了一个scratch数据,分享了一个简单的代码
a <- c(1,4,9,11,14,15,16,19,21,24,26,27,28,32,33,34,36,38,43,45,46,47,48,52,
56,60,66,72,75,76,77,78,79,80,127,130,133)
df = data.frame(
x = c("uiagdsjgcjkh bijacydgasxdhsfkajdh,cnfwkeyrg,urnyhvguirwljbhgkjgjgdkgkdgkgdkgdkgdkgdkgdkgdkgdkdgkdgkdgkdgkjdgkdwjbiuayeiuy ke,ynh lgdiyl",
"kjhfkjsdlfkojjhgckjasnhjhckjsybsanhdsabtgchbtsjahasijhcndkuysefiuwyhsnidxjnkausetfba jwf,mycaiusftbbawubbctejdgkjdghjgdduiacwyftacbm"))
# > df
# x
# 1 uiagdsjgcjkh bijacydgasxdhsfkajdh,cnfwkeyrg,urnyhvguirwljbhgkjgjgdkgkdgkgdkgdkgdkgdkgdkgdkgdkdgkdgkdgkdgkjdgkdwjbiuayeiuy ke,ynh lgdiyl
# 2 kjhfkjsdlfkojjhgckjasnhjhckjsybsanhdsabtgchbtsjahasijhcndkuysefiuwyhsnidxjnkausetfba jwf,mycaiusftbbawubbctejdgkjdghjgdduiacwyftacbm
df1 <- data.frame(lapply(df, function(x) lapply(seq_along(a), function(i){
if (i==length(a))
substr(x,a[i],nchar(as.character(x)))
else
substr(x,a[i],a[i+1]-1)}
)))
colnames(df1)=paste0("x",1:dim(df1)[2])
df1
# x1 x2 x3 x4 x5 x6 x7 x8 x9 x10 x11 x12 x13 x14 x15 x16 x17 x18 x19 x20 x21
# 1 uia gdsjg cj kh b i jac yd gas xd h s fkaj d h ,c nf wkeyr g, u r
# 2 kjh fkjsd lf koj j h gck ja snh jh c k jsyb s a nh ds abtgc hb t s
# x22 x23 x24 x25 x26 x27 x28 x29 x30 x31 x32 x33
# 1 n yhvg uirw ljbh gkjgjg dkgkdg kgd k g d k g
# 2 j ahas ijhc ndku ysefiu wyhsni dxj n k a u s
# x34 x35 x36 x37
# 1 dkgdkgdkgdkgdkdgkdgkdgkdgkjdgkdwjbiuayeiuy ke,y nh lgd iyl
# 2 etfba jwf,mycaiusftbbawubbctejdgkjdghjgdduiacwy fta cbm
似乎 readr
包(Hadley 的 tidyverse 的一部分)提供了一种更快的解决方案来一次性读取和拆分固定宽度的文件。
Dropbox 上给定的样本文件在我的系统上花费了 0.17 秒的时间 来读入并且 return 65,926 × 37 data.frame.
library(readr)
a <- c(1,4,9,11,14,15,16,19,21,24,26,27,28,32,33,34,36,38,43,45,46,47,48,52,56,60,66,72,
75,76,77,78,79,80,127,130,133)
z <- read_fwf("R71252L01.TXT", fwf_widths(diff(c(a, 142))),
col_types = stringr::str_dup("c", length(a)))
输出是一个 tibble,一个改进的 data.frame
:
print(z, n = 3, width = Inf)
# A tibble: 65,926 × 37
X1 X2 X3 X4 X5 X6 X7 X8 X9 X10
<chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
1 000 37773 71 252 1 1 012 05 005 01
2 000 37773 71 252 1 1 012 05 005 01
3 000 37773 71 252 1 1 012 05 005 01
X11 X12 X13 X14 X15 X16 X17 X18 X19 X20
<chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
1 1 2 0110 1 2 01 01 00000 01 1
2 1 2 0110 1 2 02 01 00000 01 1
3 1 2 0110 1 2 03 01 00000 01 1
X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
<chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
1 1 <NA> 6538 4001 <NA> 120314 310314 115 2 2
2 1 <NA> 6538 4001 <NA> 120314 310314 90 2 2
3 1 <NA> 6538 4001 <NA> 130314 310314 90 2 2
X31 X32 X33 X34 X35 X36 X37
<chr> <chr> <chr> <chr> <chr> <chr> <chr>
1 2 2 2 <NA> 1 2 21433
2 2 2 2 <NA> 1 2 21433
3 2 2 2 <NA> 1 2 21433
解释
您可以指定字段宽度或字段的开始和结束位置。使用
diff
从给定的起始位置a
计算宽度需要较少的编码。但是,必须以任何方式指定结束位置 (142)。为了与 Q 保持一致,我强制所有列的类型为
character
,参数为col_types = stringr::str_dup("c", length(a))
。如果 OP 需要列为其他类型,可以根据需要指定或依赖内置类型识别,请参见help("read_fwf")
。我也先尝试了
read.fwf()
,但这是 数量级的慢 (耗时 32.7 秒)。