我在一个固定宽度的文件中有时间序列数据,其中观察行(n 根据样本大小而变化)出现在包含重要元数据(即样本编号、日期等)的“标题”行下。两种类型的行都包含字母数字字符。它看起来像这样(为了便于阅读,缩短了字符串:
4 64001416230519844TP blahblah
5416001130 1 F 492273
5416001140 3 F 492274
5416001145 1 F 492275
5416001150 19 F 492276
5416001155 21 F 492277
5416001160 21 F 492278
5416001165 13 F 492279
5416001170 3 F 492280
5416001180 1 F 492281
4 64001544250619844RA blahblah
5544001125 1 F 492291
5544001130 3 F 492292
5544001135 4 F 492293
5544001140 11 F 492294
5544001145 13 F 492295
4 64002544250619844RA blahblah
etc.
标题行由字符串 == 4 中的第一个字符区分,共有 89 个字符。观察行 == 5 并且有 24 个字符。
我想要将标题行粘贴到每个后续观察行(数据子集),以便稍后我可以使用 read_fwf 解析字符串,并确保我可以根据标题行中包含的信息对每个观察进行排序。我不在乎是否删除了原始标题行。像这样:
5416001130 1 F 492273 4 64001416230519844TP blahblah
5416001140 3 F 492274 4 64001416230519844TP blahblah
5416001145 1 F 492275 4 64001416230519844TP blahblah
5416001150 19 F 492276 4 64001416230519844TP blahblah
5416001155 21 F 492277 4 64001416230519844TP blahblah
5416001160 21 F 492278 4 64001416230519844TP blahblah
5416001165 13 F 492279 4 64001416230519844TP blahblah
5416001170 3 F 492280 4 64001416230519844TP blahblah
5416001180 1 F 492281 4 64001416230519844TP blahblah
5544001125 1 F 492291 4 64001544250619844RA blahblah
5544001130 3 F 492292 4 64001544250619844RA blahblah
5544001135 4 F 492293 4 64001544250619844RA blahblah
5544001140 11 F 492294 4 64001544250619844RA blahblah
5544001145 13 F 492295 4 64001544250619844RA blahblah
etc...
我找到的最接近的解决方案是这里的fwf 文件,每 5 行有一个标题,标题是字符和观察数字
提供的解决方案是一个循环,它迭代地滚动行并测试它们是字符还是数字,然后将它们相应地粘贴在一起。
text <- readLines('/path/to/file') # read in the file
split_text <- strsplit(text, "\\s+") # split each line on whitespace
for (line in split_text) { # iterate through lines
numeric_line <- suppressWarnings(as.numeric(line)) # try to convert the current line into a vector of numbers
if (is.na(numeric_line[[1]])) { # if it fails, we know we're on a header line
header <- line
} else {
for (i in seq(1, length(line), 2)) { # otherwise, we're on a data line, so take two numbers at once
print(c(header, line[[i]], line[[i+1]])) # and output the latest header with each pair of values
}
}
}
我试图通过首先使用 read.fwf() 或 read_fwf() 读取 fwf 并将第一个字符定义为一列来区分标题和观察结果,以使其适应我的数据:
packages = c('tidyverse','rgdal','car','audio','beepr','xlsx','magrittr','lubridate','RColorBrewer','haven')
invisible(lapply(packages, function(x) {if (!require(x, character.only = T)) {install.packages(x);require(x)}}))
DF <- read.fwf("directory/.dat", widths = c(1, 88), header = FALSE)
我的适应:
newdf <- for (i in DF) { # iterate through lines
if (DF$V1 == 4) { # if true, we know we're on a header row
header <- i
} else {
for (i in seq(1, length(DF$V2), 1)) { # otherwise = observation row
print(c(header, DF$V2[[i]], DF$V2[[i+1]])) # and output the latest header with each observation until you hit another header
}
}
}
#this is very slow and/or does not work
# I get the following error message
#Warning messages:
1: In if (DF$V1 == 4) { :
the condition has length > 1 and only the first element will be used
我还尝试通过 nchar() 听者 =89 和观察 = 24 指定标题与观察行。我意识到这里的循环解决方案可能是使用 ifelse 但出现了另一个问题。数据集长约 39700 行,我一直在获取新数据。循环将需要很长时间...
我想用 data.table 或 dplyr 语法来做到这一点。
我已经尝试按照这些帖子玩 dplyr::lag:dplyr 示例 1 和dplyr 示例 2,并接近我想要的:
newdf<-DF %>%
mutate(new = replace(lag(V2), V1 != '5', NA))
但是正如您所看到的,新列仅粘贴上一行的信息......正如 lag() 应该做的那样。
任何帮助将不胜感激,在此先感谢您。
作为旁注。这些数据以前在 SAS 中处理过,但因为我不做 SAS,所以你去吧。如果有帮助,我确实有 SAS 代码:
DATA A1;
FILENAME FREQLONG 'dir/FL.DAT';
INFILE FREQLONG;
INPUT
TYPE 1 @ ;
IF TYPE EQ 4 THEN LINK LIGNE4;
IF TYPE EQ 5 THEN DELETE;
RETURN;
LIGNE4:
INPUT var1 $ 6 - 8
var2 $ 9 - 11
var3 12 - 13
var4 14 - 15
var5 18 - 19
var6 $ 20 - 22
var7 $ 44 - 46
var8 $ 78;
DATA A2;
FILENAME FREQLONG 'dir/FL.DAT';
INFILE FREQLONG;
INPUT
TYPE 1 @ ;
IF TYPE EQ 4 THEN DELETE;
IF TYPE EQ 5 THEN LINK LIGNE5;
RETURN;
LIGNE5:
INPUT var1 $ 5 - 7
var2 $ 2 - 4
varz 8 - 10
vara 11 - 13
varb $ 15;
DATA A3;
SET A1;
PROC SORT;
BY var1 var2;
RUN;
DATA A4;
SET A2;
PROC SORT;
BY var1 var2;
RUN;
DATA A5;
MERGE A4 A3;
BY var1 var2;
RUN;
如您所见,它拆分文件、对变量进行排序、合并它们。然而,这是逐年完成的,我想多年来都使用一个文件。