用可变字段重新排列Excel / R中的多个单元格内容

时间:2018-07-17 10:50:38

标签: r excel tidyverse

对于这个问题,我有点数据困扰。 我有一个通过复制粘贴从网站生成的Excel中的表格,其中每一行代表一个示例。在这一行中,有一个特定的字段,其中包含可变数量的单元格。 我附上了屏幕截图,以便您可以轻松理解我的意思:

excel screenshot 1

现在,我要做的是将这些字段中的每一个都放在单独的列中。如果这是固定数量的行,我将简单地按“选择性粘贴”进行转置,然后在固定数量的字段处中断结果行,以使所有内容保持整齐。 但是,每行的字段数会发生变化;并非所有样本都具有相同数量的属性,这意味着转置整个列是不够的。我现在花了几分钟的时间来处理所有内容并手动移动单元格,以便在空白处没有值,但是每行的属性数保持不变:

excel screenshot 2

但是,这很繁琐,耗时,并且由于我有500多个条目,因此将永远花光。

我一点也不精通excel脚本,但是我对R的基础知识有一定的了解。我要解决的主要问题是,如果我将此表作为文本文件导入R中,则每个单元格在该列中将单独分配一行,使折叠变得非常复杂。

这是我到目前为止提出的:

#This is the data I need to wrangle
tmp <- read.delim("pdata.txt", header = T, stringsAsFactors = F)
> head(tmp)
            Title             Source.name             Disease.state    Sex Age
1 LT000842RU_CTRL Flash frozen whole lung                   Control 1-Male  75
2                                                                           NA
3                                                                           NA
4                                                                           NA
5  LT001600RL_ILD Flash frozen whole lung Interstitial lung disease 1-Male  54
6                                                                           NA
  Gold.stage              Characteristics Ild.subtype Pneumocystis.colonization
1  0-At Risk       smoker?: 2-Ever (>100)
2            %predicted fev1 (pre-bd): 96
3             %predicted fvc (pre-bd): 97
4                     %predicted dlco: 78
5               %emphysema (f-950): 1.903   2-UIP/IPF
6                  smoker?: 2-Ever (>100)

如您所见,“标题”列中存在空白,这是由“特征”列中具有相同标题的更多条目引起的。

#Extremely ugly series of gsub to make for compatible colnames (no spaces, no dashes, etc)
d = sapply(tmp[,7], function(x) {gsub(x, pattern = " ", replacement = "_", fixed = T)})
dd = sapply(d, function(x) {gsub(x, pattern = "%", replacement = "", fixed = T)})
dd = sapply(dd, function(x) {gsub(x, pattern = "_(f-950):_", replacement = " ", fixed = T)})
dd = sapply(dd, function(x) {gsub(x, pattern = "?:", replacement = "", fixed = T)})
dd = sapply(dd, function(x) {gsub(x, pattern = "smoker_", replacement = "smoker ", fixed = T)})
dd = sapply(dd, function(x) {gsub(x, pattern = ":_", replacement = " ", fixed = T)})
dd = sapply(dd, function(x) {gsub(x, pattern = "(", replacement = "", fixed = T)})
dd = sapply(dd, function(x) {gsub(x, pattern = ")", replacement = "", fixed = T)})
dd = sapply(dd, function(x) {gsub(x, pattern = "-", replacement = "_", fixed = T)})


  #Use the character vector that has been gsubbed as the attributes column in the df
tmp[,7] = dd


#Take the rows that are not empty, i.e. those that have the name of the sample and will be the starting rows for the attributes
    nonempty = which(tmp[,1] != "")
    jumps = nonempty[2:length(nonempty)]-nonempty[1:length(nonempty)-1]
    jumps = c(jumps, 0)

#Make dummy columns with the same names as the gsubbed attributes
tmp$emphysema = tmp[,1]
tmp$smoker = tmp[,1]
tmp$predicted_fcv_pre_bd = tmp[,1]
tmp$predicted_fev1_pre_bd = tmp[,1]
tmp$predicted_fev1_post_bd = tmp[,1]
tmp$predicted_fcv_post_bd = tmp[,1]
tmp$predicted_dlco = tmp[,1]

#This is a loop to fill in the columns with the values extracted from the gsubbed attributes column
for(i in 1:length(nonempty))
{
    a = as.data.frame(tmp[seq(nonempty[i], (nonempty[i]+jumps[i]-1),by = 1),7])
    chars = colnames(tmp[,10:ncol(tmp)])
    for (j in chars)
    {
        gg = as.character(a[grep(pattern = j, x = a[,1]),1])
        if(length(gg) != 0) tmp[nonempty[i],j] = as.character(unlist(strsplit(gg, split = " "))[2]) else tmp[nonempty[i],j] = NA
    }
}
# Make the new df by only taking the rows with samples
tmp2 = tmp[nonempty,]

#This is the resulting data frame:
> head(tmp2)
                          Title             Source.name
LT000216LL_ILD   LT000216LL_ILD Flash frozen whole lung
LT000379LU_ILD   LT000379LU_ILD Flash frozen whole lung
LT000842RU_CTRL LT000842RU_CTRL Flash frozen whole lung
LT001600RL_ILD   LT001600RL_ILD Flash frozen whole lung
LT001796RU_CTRL LT001796RU_CTRL Flash frozen whole lung
LT002410RM_ILD   LT002410RM_ILD Flash frozen whole lung
                            Disease.state      Sex Age Gold.stage
LT000216LL_ILD  Interstitial lung disease 2-Female  70
LT000379LU_ILD  Interstitial lung disease   1-Male  63
LT000842RU_CTRL                   Control   1-Male  75  0-At Risk
LT001600RL_ILD  Interstitial lung disease   1-Male  54
LT001796RU_CTRL                   Control   1-Male  48  0-At Risk
LT002410RM_ILD  Interstitial lung disease   1-Male  52
                   Characteristics                       Ild.subtype
LT000216LL_ILD     emphysema 0.051                         2-UIP/IPF
LT000379LU_ILD  smoker 2_Ever_>100 9-Hypersensitive Pneumonitis (HP)
LT000842RU_CTRL smoker 2_Ever_>100
LT001600RL_ILD     emphysema 1.903                         2-UIP/IPF
LT001796RU_CTRL smoker 2_Ever_>100
LT002410RM_ILD      emphysema 0.03                         2-UIP/IPF
                Pneumocystis.colonization emphysema      smoker
LT000216LL_ILD                                0.051     3_Never
LT000379LU_ILD                                 <NA> 2_Ever_>100
LT000842RU_CTRL                                <NA> 2_Ever_>100
LT001600RL_ILD                                1.903 2_Ever_>100
LT001796RU_CTRL                                <NA> 2_Ever_>100
LT002410RM_ILD                                 0.03 2_Ever_>100
                predicted_fcv_pre_bd predicted_fev1_pre_bd
LT000216LL_ILD                  <NA>                    56
LT000379LU_ILD                  <NA>                    67
LT000842RU_CTRL                 <NA>                    96
LT001600RL_ILD                  <NA>                    40
LT001796RU_CTRL                 <NA>                   107
LT002410RM_ILD                  <NA>                    56
                predicted_fev1_post_bd predicted_fcv_post_bd predicted_dlco
LT000216LL_ILD                    <NA>                  <NA>             36
LT000379LU_ILD                    <NA>                  <NA>             42
LT000842RU_CTRL                   <NA>                  <NA>             78
LT001600RL_ILD                    <NA>                  <NA>             16
LT001796RU_CTRL                    110                  <NA>            107
LT002410RM_ILD                      60                  <NA>             63

现在,尽管我对这个结果感到满意,但花了一些时间做饭,而且它非常不灵活(非常适合于此特定数据集),所以我想知道以下内容:

  1. Excel中是否有针对这种情况的快速修复程序?
  2. 或者,或者甚至更好:是否有底数/底数 在R中处理它的方式不像     我想出了一个?

提前谢谢!

1 个答案:

答案 0 :(得分:0)

假设原始数据中的大单元格是合并的单元格, 在 openxlsx tidyr 的帮助下,这非常简单。无论如何,我都会赞同@RonRosenfeld的建议(在评论中),即建立到远程源的数据连接,而不是复制粘贴。

我创建了一个简化的示例文件messy.xlsx(请参阅文章末尾的代码),以演示数据处理过程的一个选项:

Messy Excel data.

您可以首先使用read.xlsx()读取Excel文件,并保留 合并单元格所隐含的结构,然后是separate()spread() 将不同的特征分成自己的列:

library(openxlsx)
library(tidyr)

# Repeat merged cell value accross all cells
messy <- read.xlsx("messy.xlsx", fillMergedCells = TRUE)

# Create a column for each characteristic
messy %>%
  separate(
    characteristics,
    into = c("variable", "value"),
    sep = ": "
  ) %>% 
  spread(variable, value)
#>   subject a b    c
#> 1     101 1 2    3
#> 2     102 2 8 <NA>

样本数据:

library(openxlsx)

wb <- createWorkbook()
addWorksheet(wb, "Sheet 1")

df <- data.frame(
  subject = c(101, NA, NA, 102, NA),
  characteristics = c("a: 1", "b: 2", "c: 3", "a: 2", "b: 8")
)

writeData(wb, 1, df)

mergeCells(wb, 1, 1, 2:4)
mergeCells(wb, 1, 1, 5:6)

saveWorkbook(wb, "messy.xlsx")

reprex package(v0.2.0.9000)于2018-07-17创建。