在发布我的原始答案后,我意识到数据可能与我的假设不同,因为原始帖子中的内容引用了原始数据中的第 1 列和第 2 列。如果数据如下所示,则有一个相对简单的答案,将dplyr 与tidyr::pivot_wider() 结合起来。
首先,我们将读取数据并打印结果数据框,两列包括数据值和列名。
textFile <- "col1|col2
XYZCo|Company
123 Main Street|Address
Yourtown, MA 12345|CityStZip
Joe Smith|Contact
20-234-56/3|Contract
Process for Work|Title
ZZTop Co|Company
123 Jefferson Street|Address
Chicago, IL 60636|CityStZip
Jane Doe|Contact
23-274-11/3|Contract
Yet Another One|Title"
data <- read.csv(text = textFile,header = TRUE, sep="|")
数据框如下所示:
> data
col1 col2
1 XYZCo Company
2 123 Main Street Address
3 Yourtown, MA 12345 CityStZip
4 Joe Smith Contact
5 20-234-56/3 Contract
6 Process for Work Title
7 ZZTop Co Company
8 123 Jefferson Street Address
9 Chicago, IL 60636 CityStZip
10 Jane Doe Contact
11 23-274-11/3 Contract
12 Yet Another One Title
为了将数据框转换为宽格式整洁的数据,我们需要添加一个 ID 列来区分一个观察结果和其他观察结果。我们可以为此使用dplyr::mutate(),以及ceiling() 函数。需要ceiling() 函数,因为我们希望每 6 行输入数据的 ID 值保持不变。当我们将seq_along() 的结果除以 6 时,它会生成所需的向量。
添加 ID 列后,转为宽格式相对简单。
library(dplyr)
library(tidyr)
data %>% mutate(id = ceiling(seq_along(col1)/6)) %>%
pivot_wider(.,id,names_from=col2,values_from=col1)
...和输出:
# A tibble: 2 x 7
id Company Address CityStZip Contact Contract Title
<dbl> <chr> <chr> <chr> <chr> <chr> <chr>
1 1 XYZCo 123 Main Street Yourtown, MA 1… Joe Smi… 20-234-56… Process for…
2 2 ZZTop Co 123 Jefferson S… Chicago, IL 60… Jane Doe 23-274-11… Yet Another…
原答案
这个问题的有趣挑战是观察跨越 6 行数据,但不是在固定的记录布局中,所以我们不能使用 read.fwf() 或 read.fortran() 来读取文件。
相反,我们将使用readLines() 将数据读入向量,然后将其写入临时文件,将每 6 行组合成一个输出记录。最后,我们将使用read.csv() 读取重构后的数据。
原始帖子不清楚列名是否可以与原始数据文件中的其余数据区分开来,因此此解决方案假定我们需要将它们从所需的结果数据框中解析出来。
textFile <- "XYZCo Company
123 Main Street Address
Yourtown, MA 12345 CityStZip
Joe Smith Contact
20-234-56/3 Contract
Process for Work Title
ZZTop Co Company
123 Jefferson Street Address
Chicago, IL 60636 CityStZip
Jane Doe Contact
23-274-11/3 Contract
Yet Another One Title"
首先我们用readLines()将数据读入一个字符向量。
dataVector <- readLines(textConnection(textFile))
接下来,我们从向量中剔除列名数据。由于只有6个列名,所以我很懒,只是反复使用sub()。原题表示列名是在数据加载到R后添加的,所以这段代码可能不需要。
# clean column names from raw data
dataVector <- sub("Company","",dataVector)
dataVector <- sub("Address","",dataVector)
dataVector <- sub("CityStZip","",dataVector)
dataVector <- sub("Contact","",dataVector)
dataVector <- sub("Contract","",dataVector)
dataVector <- sub("Title","",dataVector)
接下来,我们循环遍历向量,并将每 6 行组合成一个输出记录,使用管道 | 作为分隔符,因为数据在 CityStZip 字段中包含逗号。
# write to tempfile as pipe separated values
tmpFile <- "./data/tmpfile.csv"
counter <- 0
outLine <- NULL
for(i in 1:length(dataVector)){
counter <- counter + 1
if(counter == 1 ) outLine <- dataVector[i]
else outLine <- paste(outLine,dataVector[i],sep="|")
if(counter == 6) {
cat(outLine,file = "./data/tmpfile.csv",sep="\n",append=TRUE)
counter <- 0
outLine <- NULL
}
}
最后,我们读取刚刚创建的文件,并指定sep = '|' 作为列之间的分隔符。我们还使用col.names 参数来设置列名。
colNames <- c("Company","Address","CityStZip","Contact","Contract","Title")
data <- read.csv("./data/tmpfile.csv",header = FALSE,sep = "|",
col.names = colNames)
...和输出:
> data
Company Address CityStZip Contact Contract
1 XYZCo 123 Main Street Yourtown, MA 12345 Joe Smith 20-234-56/3
2 ZZTop Co 123 Jefferson Street Chicago, IL 60636 Jane Doe 23-274-11/3
Title
1 Process for Work
2 Yet Another One