在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])
dftidyverse
解决方案:
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
的列。