【问题标题】:Re-Format data with multiple headers to long format with one header row becoming data in a new column将具有多个标题的数据重新格式化为长格式,一个标题行成为新列中的数据
【发布时间】:2020-05-13 22:11:03
【问题描述】:

我经常收到使用多个标题和合并单元格格式化的数据(是的..excel)。通常,这些数据以表示样本站点的 2+ 个合并单元格的形式出现,位于代表该站点感兴趣参数的列中的许多观察值的顶部。我正在使用“openxlsx”包通过如下所示的 read.xlsx 函数读取数据(不会运行仅供参考):

read.xlsx('Mussels.xlsx',
              detectDates = T,
              sheet = 2,
              fillMergedCells = T, 
              startRow = 2)

一个例子:我目前正在处理侵入性贻贝调查数据,其中我有 25 个长度,用于 14 个站点中的每个站点的两个物种,为了方便起见,我在此进行了缩写:

lendat <- data.frame(site.a = c("species.1",1,1,1,1),
                     site.a = c("species.2",2,2,2,2), 
                     site.b = c("species.1",3,3,3,3),
                     site.b = c("species.2",4,4,4,4),
                     check.names = F)

我希望能够编写一些代码,将这些数据重新格式化为长格式,其中列名成为名为“site”的新列下的值,第一行数据成为其他列名,表示每个物种的长度如下:

data_form <- data.frame(site = c(rep("site.a", 4), rep("site.b",4)),
                        species.1 = c(1,1,1,1,3,3,3,3),
                        species.2 = c(2,2,2,2,4,4,4,4))

根据@Ronak Shah 的回答更新

将下面接受的答案中的代码与实际数据一起使用会导致没有数据的小标题。我发现当数据中引入十进制值(实际数据包含十进制值)时,过滤步骤会出现问题。我认为这是一个数据格式问题(示例数据都是因素),但即使这是真的,十进制数据也会更改为 NA。见例子:

lendat <- data.frame(site.a = c("species.1", 1.1,2.2,3,4),
                     site.a = c("species.2",5,6,7,8), 
                     site.b = c("species.1", 9,10,11,12),
                     site.b = c("species.2",13,14,15,16),
                     check.names = F)
str(lendat)
'data.frame':   5 obs. of  4 variables:
 $ site.a: Factor w/ 5 levels "1.1","2.2","3",..: 5 1 2 3 4
 $ site.a: Factor w/ 5 levels "5","6","7","8",..: 5 1 2 3 4
 $ site.b: Factor w/ 5 levels "10","11","12",..: 5 4 1 2 3
 $ site.b: Factor w/ 5 levels "13","14","15",..: 5 1 2 3 4

我将管道代码逐行拆分

#Get data in long format
pivot_longer(junk, cols = everything(), names_to = 'site') %>%
  #Create a new column with column names
  mutate(col = paste0('species', .copy)) %>%
  #Remove the values from the first row
  filter(!grepl('\\D', value)) %>%
  #Remove .copy column which was created
  select(-.copy) %>%
  #Group by the new column
  group_by(col) %>%
  #Add a row index
  mutate(row = row_number()) %>%
  #Get data in wide format
  pivot_wider(names_from = col, values_from = value) %>%
  #Remove row index
  select(-row) %>%
  #Arrange data according to site information
  arrange(site)

x <- pivot_longer(junk, cols = everything(), names_to = 'site')
x
x <- mutate(x, col = paste0('species', .copy))
x
x <- filter(x, !grepl('\\D', value))
x
x <- select(.data = x, -.copy)
x
x <- group_by(x, col)
x
x <- mutate(x, row = row_number())
x
x <- pivot_wider(x, names_from = col, values_from = value)
x
x <- select(x, -row)
x
x <- arrange(x, site)
x

代码执行但将 NA 留在最后的 tibble 中。

【问题讨论】:

    标签: r


    【解决方案1】:

    使用dplyrtidyr

    library(dplyr)
    library(tidyr)
    
    #Get data in long format
    pivot_longer(lendat, cols = everything(), names_to = 'site') %>%
        #Create a new column with column names
        mutate(col = paste0('species', .copy)) %>%
        #Remove the values from the first row
        filter(!grepl('[A-Za-z]', value)) %>%
        #Remove .copy column which was created
        select(-.copy) %>%
        #Group by the new column
        group_by(col) %>%
        #Add a row index
        mutate(row = row_number()) %>%
        #Get data in wide format
        pivot_wider(names_from = col, values_from = value) %>%
        #Remove row index
        select(-row) %>%
        #Arrange data according to site information
        arrange(site)
    
    
    #   site   species1 species2
    #  <chr>  <chr>    <chr>   
    #1 site.a 1.1      5       
    #2 site.a 2.2      6       
    #3 site.a 3        7       
    #4 site.a 4        8       
    #5 site.b 9        13      
    #6 site.b 10       14      
    #7 site.b 11       15      
    #8 site.b 12       16      
    

    【讨论】:

    • 谢谢,这适用于示例。扩展到我更大的数据集被证明是棘手的。你能告诉我“\\D”模式代表什么吗?我在帮助文档中发现它是用于数字的?
    • \\D 是检测非数字。所以使用filter(!grepl('\\D', value)) 我们删除了所有没有数字的行。所以它会删除像"species.1""species.2" 等。
    • 这是有道理的。看来问题与我的实际数据具有十进制值这一事实有关。这些在过滤步骤中变成了 NA。我编辑了上面的问题以反映这个问题。有什么想法吗?
    • 所以它在过滤步骤中检测小数点并删除我认为的所有数据?
    • 查看更新的答案。我改用filter(!grepl('[A-Za-z]', value))
    猜你喜欢
    • 1970-01-01
    • 2016-07-12
    • 1970-01-01
    • 2021-03-21
    • 1970-01-01
    • 2014-06-07
    • 2017-11-12
    • 1970-01-01
    • 2019-03-18
    相关资源
    最近更新 更多