将合同信息的柱状 table 转换为行

convert a columnar table of contract info into rows

我有大量 table 的合同信息(数百份合同),全部收集在 table 的单个列中。每个合约占据 6 个连续行。我已经能够添加另一列 (CAT),指示列中每一行的内容:公司、地址、CitySTZip、联系人、合同、职务。 [使用 R]

添加第二列以表示列名后的数据的可重现版本,数据如下所示:

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

我想重新排序所有数据,以便每个合约在数据 table 中占据一行,CAT 值作为列 headers。

根据对下面发布的答案的评论,使用 for() 循环重新格式化文件的尝试未成功。

for(i in 1:nrow(data)){
   for(j in 1:6){
      # got stuck here... 
   }
} 

所需的输出如下所示:

Company Address           CitySTZip            Contact     Contract      Title

XYZCo 123 Main Street   Yourtown, MA 12345   Joe Smith   20-234-56/3   Process for Work

在 post 我的原始答案之后,我意识到数据可能与我的假设不同,因为原始 post 中的内容引用了第 1 列和第 2 列原始数据。如果数据如下所示,则有一个相对简单的答案,将 dplyrtidyr::pivot_wider().

组合在一起

首先,我们将读取数据并打印生成的数据框,2 列包括数据值和列名。

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().

读取重塑后的数据

原文post并不清楚列名是否与原始数据文件中的其余数据区分开来,因此该解决方案假设我们需要将它们从所需的结果数据中解析出来帧.

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