在R中转换数据

在R中转换数据,r,reshape,tidyr,R,Reshape,Tidyr,我有导入时看起来像这样的数据 ID col1 col2 col3 col4 1 a e i r j s k t 2 b f l u m v n w o x 3 c g p y 4 d h q z 并希望对其进行转换,以便每行有一个唯一的ID,即: ID co

我有导入时看起来像这样的数据

ID col1 col2 col3 col4
1  a    e    i    r
             j    s
             k    t
2  b    f    l    u
             m    v
             n    w
             o    x
3  c    g    p    y
4  d    h    q    z
并希望对其进行转换,以便每行有一个唯一的ID,即:

ID col1 col2 col3 col4 col5 col6 col7 col8 col9 col10
1  a    e    i    r    j    s    k    t
2  b    f    l    u    m    v    n    w    o    x
3  c    g    p    y
4  d    h    q    z
易于理解的数据形式:

df <- data.frame(ID = c(1, NA, NA, 2, NA, NA, NA, 3, 4),
                 col1 = c('a', NA, NA, 'b', NA, NA, NA, 'c', 'd'),
                 col2 = c('e', NA, NA, 'f', NA, NA, NA, 'g', 'h'),
                 col3 = letters[9:17],
                 col4 = letters[18:26])

df
tidyverse
解决方案:

df %>%
  mutate(ID = zoo::na.locf(ID)) %>%
  mutate(row = row_number()) %>%
  tidyr::gather(col, val, col1:col4) %>%
  filter(!is.na(val)) %>%
  arrange(ID, row, col) %>%
  select(-row) %>%
  group_by(ID) %>%
  mutate(col = row_number()) %>%
  mutate(col = paste0('col', stringr::str_pad(col, side = 'left', pad = '0', width = 2))) %>%
  tidyr::spread(col, val)

下面是一个结合使用
dplyr
tidyr
以及一些基础的解决方案:

library(dplyr)
library(tidyr)

df <- fill(df, ID, .direction = 'down')
numCols <- max(sapply(split(df, df$ID), function(x) sum(!is.na(x[, -1]))))

df %>%
  group_by(ID) %>%
  do(summarise(., l = paste(unlist(.[, -1])[!is.na(unlist(.[, -1]))], collapse = ' '))) %>%
  separate(l, into = paste0('col', 1:numCols), sep = ' ')
库(dplyr)
图书馆(tidyr)
df%
do(摘要(,,l=粘贴(未列出(,-1])[!is.na(未列出(,-1])],折叠=“”))%>%
分离(l,into=paste0('col',1:numCols),sep='')
结果如下:

     ID  col1  col2  col3  col4  col5  col6  col7  col8  col9 col10
* <dbl> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
1     1     a     e     i     j     k     r     s     t  <NA>  <NA>
2     2     b     f     l     m     n     o     u     v     w     x
3     3     c     g     p     y  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>
4     4     d     h     q     z  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>
ID col1 col2 col3 col4 col5 col6 col7 col8 col9 col10
*           
1 1 a e i j k r s t
2 2 b f l m n o u v w x
3CGPy
4dhqz

有一点需要注意,长格式对于这种情况几乎总是更有用,有两种选择:

库(tidyverse)
df%填充(ID)%%>%
聚集(变量,值,-ID)%>%
落差_na(val)%>%
分组依据(ID)%>%
变异(var=sprintf('col%02d',row_number()))%>%
价差(var,val)
#>#A tible:4×11
#>#组:ID[4]
#>ID col01 col02 col03 col04 col05 col06 col07 col08 col09 col10
#> *           
#>1 1 a e i j k r s t
#>2 2 b f l m n o u v w x
#>3CGPy
#>4dhqz
或者将所有内容折叠为字符串并分开:

df%>%mutate_at(vars(-ID),as.character)%>%
填充(ID)%>%
分组依据(ID)%>%
总结(lets=toString(na.省略(c(col1,col2,col3,col4)))%>%
分开(let,sprintf('col%02d',1:10),fill='right')
#>#A tible:4×11
#>ID col01 col02 col03 col04 col05 col06 col07 col08 col09 col10
#> *           
#>1 1 a e i j k r s t
#>2 2 b f l m n o u v w x
#>3CGPy
#>4dhqz

基本R有时还不错:

tmp <- na.omit(data.frame(id=cummax(replace(df$ID, is.na(df$ID), 0)), col=unlist(df[-1]) ))
reshape(transform(tmp, time=ave(id,id,FUN=seq_along)), direction="wide", idvar="id", sep="")

#      id col1 col2 col3 col4 col5 col6 col7 col8 col9 col10
#col11  1    a    e    i    j    k    r    s    t <NA>  <NA>
#col14  2    b    f    l    m    n    o    u    v    w     x
#col18  3    c    g    p    y <NA> <NA> <NA> <NA> <NA>  <NA>
#col19  4    d    h    q    z <NA> <NA> <NA> <NA> <NA>  <NA>

tmp您能提供数据的dput吗?我不确定第3列和第4列的值是什么,非常好。比我下面的解决方案更简单。我更喜欢第一个版本,因为它独立于列数(类似于我的目标)。顺便说一句,你的第二个解决方案是硬编码10,这在“更完整的数据”中可能不正确。这是更好的计算,因为我正在做。另一个原因,我喜欢第一个。是的,你可以在
摘要
步骤中计算长度,但是如果你硬编码输入列的话,那就不值得了。另一个老套的解决方法是,只需留出比需要更多的列,然后删除所有完全是
NA
的列。