2

编辑:

从基于名为 a 的变量的文本中,我想获得一个表格,其中将展开描述单元格。

a <- 
  "
   category     variable    description                    value
   A            A           This is variable named as A    123
                            which is responsible for sth
                B           This is variable named as B    222.1 
                            which is responsible for sth
                            else
   B            A           This is sth                    2
                                                           out of 4  
   Other c      Other va    This is variable named as      222  
   ategory      riable      other variable which can be   
                            nullable
                Other va    This is variable named as      0  
                riable A    other variable A which can   
                            be nullable
  "

我想要的结果:

在此处输入图像描述

4

4 回答 4

4

实现所需结果的一种选择是将变量读取为固定宽度的文件,使用例如readr::read_fwf和一些额外的数据整理步骤,我使用tidyrand dplyr

library(dplyr)
library(tidyr)
library(readr)

df <- readr::read_fwf(file = a, skip = 1)
names(df) <- unlist(df[1, ])
df <- df[-1,]
df %>% 
  filter(!is.na(description)) %>% 
  tidyr::fill(category, variable) %>% 
  group_by(category, variable) %>% 
  summarise(description = paste(description, collapse = " "), value = value[!is.na(value)])
#> `summarise()` has grouped output by 'category'. You can override using the `.groups` argument.
#> # A tibble: 2 × 4
#> # Groups:   category [1]
#>   category variable description                                            value
#>   <chr>    <chr>    <chr>                                                  <chr>
#> 1 A        A        This is variable named as A which is responsible for … 123  
#> 2 A        B        This is variable named as B which is responsible for … 222.1
于 2022-01-14T15:22:29.763 回答
1

我很难过,现在示例已更改,因此所有单元格都可以换行。希望@stefan 有一个想法。

一些粗略的建议。

  1. 你能控制文本的创建方式吗?您的 OP 非常彻底,我假设您探索并消除了这种可能性。但是如果你有控制权(比如加宽输出参数),那是最简单最直接的。

  2. 我认为您至少需要一列来指示新行何时是新记录,以及新行何时是同一记录的延续。在您的 OP 的第一次迭代中,该variable列表明了这一点。

  3. 这个新的指标变量(称为record_id)将具有值 {1, 1, 2, 2, 2, 3, 3, 4, 4, 4, 5, 5, 5}。查看第 1行和第 2 行如何属于记录1,以及第 3-5如何属于记录2。

  4. 您可能会以某种方式以编程方式修改a字符串。也许开始readr::read_lines()并使用正则表达式来指示哪些行代表新记录。然后使用典型的 readr 函数将字符串数组转换为 data.frame。我们需要更多地了解前两列的值的规则/可重复性。鉴于您的 [gsub] 标签,我看到您最初正在考虑这一点。

  5. 或者先用 fwf 读取所有内容,然后使用rematch2创建变量以指示记录是新记录还是延续记录。这完全取决于variable.

  6. 是否a代表磁盘上的文件?换行的一致性如何?如果record_id所有文件都相同,那么您可以手动确定record_id一次,并将其添加到每个数据集中。然后类似于@stefan 和我的答案。

于 2022-01-16T18:17:55.803 回答
1

这类似于@stefans。主要区别在于这种方式需要您指定column_widthswith readr::fwf_cols()。(这可能是优点或缺点,取决于传入数据文件的一致性/稳定性。)

a <- 
"category     variable    description                    value
A            A           This is variable named as A    123
                         which is responsible for sth
             B           This is variable named as B    222.1 
                         which is responsible for sth
                         else
"
column_widths <-
  readr::fwf_cols(
    category        = 13,
    variable        = 8,
    description     = 32,
    value           = 10
  )

I(a) |> 
  readr::read_fwf(
    col_positions = column_widths,
    skip          = 1         # Because the headers are defined in `column_widths`
  ) |> 
  tidyr::fill(category, variable) |> 
  dplyr::mutate(
    value   = as.character(value),
    value   = dplyr::coalesce(value, "")
  ) |> 
  dplyr::group_by(category, variable) |> 
  dplyr::summarize(
    description = paste0(description, collapse = " "), 
    value       = as.numeric(paste0(value, collapse = " ")), 
  ) |> 
  dplyr::ungroup()

输出:

# A tibble: 2 x 4
  category variable description                 value
  <chr>    <chr>    <chr>                       <dbl>
1 A        A        This is variable named as ~  123 
2 A        B        This is variable named as ~  222.
于 2022-01-14T15:42:47.747 回答
0

我找到了一种使用@wibeasley 想法的方法,在该方法中我生成record_id,然后按此值分组。

df <- readr::read_fwf(file = a, col_positions = column_widths, skip = 2)

df <- data.table(df)
df[, notnullvar := is.na(variable)]
df[, notnullval := is.na(value)]
df$record_id = 1
for(i in 2:nrow(df)){ #not empty variable cell and not empty value then add +1 to record_id   
  if(df[i,]$notnullvar == FALSE & df[i,]$notnullval == FALSE){
    df[i,]$record_id <- df[i-1,]$record_id + 1
  }else{
    df[i,]$record_id <- df[i-1,]$record_id
  }
}
df <- df[, .(category = paste0(category, collapse = ""), 
             variable = paste0(variable, collapse = ""),
             description = paste0(description, collapse = " "),
             value = paste0(value, collapse = " ")
), by = record_id]

df[,2:5] <- lapply(df[,2:5], function(record_id) trimws(gsub("NA","",record_id)))

问题是我想从 pdf 文件中抓取表格,其中表格可能不同(列宽或各种格式的包装文本)。因此,最好准备始终包含 4 列的动态列宽。我想我可以找到字符串的长度到下一个列名的名称,例如category variable 字符串包含两列类别和变量,类别宽度为 14 和变量 10。

于 2022-01-18T08:43:23.887 回答