【问题标题】:Rearranging longitudinal data重新排列纵向数据
【发布时间】:2015-02-27 16:31:19
【问题描述】:

我有一个大致如下结构的数据集:

case Year      2001 2002 2003 2004
1    2003      0    0    0    3
2    2002      0    5    3    2
3    2001      3    3    2    2

我正在尝试对其进行重组,以便每一列代表从“年份”变量计数的第一年、第二年(等等),即:

case Year      yr1  yr2  yr3 yr4
1    2003      0    3    0    0 
2    2002      5    3    2    0
3    2001      3    3    2    2

此代码下载数据集并尝试@akrun 建议的解决方案,但失败了。

library("devtools")
df1 <- source_gist("b4c44aa67bfbcd6b72b9")

df1[-(1:2)] <- do.call(rbind,lapply(seq_len(nrow(df1)), function(i) {x <- df1[i, ]; x1 <- unlist(x[-(1:2)]); indx <- which(!is.na(x1))[1]; i <- as.numeric(names(indx))-x[,2]+1; x2 <- x1[!is.na(x1)]; x3 <- rep(NA, length(x1)); x3[i:(i+length(x2)-1)]<- x2; x3}))

这会生成:

Error in i:(i + length(x2) - 1) : NA/NaN argument
In addition: Warning message:
In FUN(1:234[[1L]], ...) : NAs introduced by coercion

如何转换数据,以便每一列代表第一年、第二年(等等),从每行的“年份”变量中的值开始计算?

【问题讨论】:

  • 我只是在看预期的输出。抱歉,我可能错过了那个关键属性。
  • 对于第一行,3 重新排列为 yr2。我这里没有连接。
  • 因为“年份”变量中指定的 yr1=2003
  • @akrun - 你在写一个新的解决方案吗?您具有一定价值的解决方案 - 通过手动编辑数据集它可以工作......
  • 看了你的预期和输入数据后,我仍然没有得到连接

标签: r data-manipulation


【解决方案1】:

这是一种可能性:

library(dplyr)
library(reshape2)

df %>%
  melt(id.vars = c("case", "Year")) %>%
  mutate(variable = as.numeric(as.character(variable)),
         yr = variable - Year + 1) %>%
  filter(variable >= Year) %>%
  dcast(case + Year ~ yr, fill = 0)

#   case Year 1 2 3 4
# 1    1 2003 0 3 0 0
# 2    2 2002 5 3 2 0
# 3    3 2001 3 3 2 2

数据:

df <- structure(list(case = 1:3, Year = c(2003L, 2002L, 2001L), `2001` = c(0L, 
0L, 3L), `2002` = c(0L, 5L, 3L), `2003` = c(0L, 3L, 2L), `2004` = c(3L, 
2L, 2L)), .Names = c("case", "Year", "2001", "2002", "2003", 
"2004"), class = "data.frame", row.names = c(NA, -3L))

【讨论】:

  • 我无法让它在真实数据上工作:library(devtools) library(dplyr) library(reshape2) df &lt;- source_gist("b4c44aa67bfbcd6b72b9") start &lt;- 1 case &lt;- seq(start, 234, 1) df1 &lt;- cbind(case, df) df1 %&gt;% melt(id.vars = c("case", "Year")) %&gt;% mutate(variable = as.numeric(as.character(variable)), yr = variable - Year + 1) %&gt;% filter(variable &gt;= Year) %&gt;% dcast(case + Year ~ yr, fill = 0) 这将返回 Error in mutate_impl(.data, dots) : object 'variable' not found - 这里应该有什么变量?
  • @histelheim 你的第三行应该是df &lt;- source_gist("b4c44aa67bfbcd6b72b9")$value
  • @Henrik 我认为您应该使用gsub('X','',variable) 而不是as.character(variable) 来替换每个变量开头的X
  • @nograpes 感谢您的评论。我使用了OP提供的数据集,变量名开头没有X(我已经添加了数据框的dput)。
【解决方案2】:

这应该会创建您正在寻找的操作。

library("devtools")
df1 <- source_gist("b4c44aa67bfbcd6b72b9")
temp <- df1[[1]]

library(dplyr); library(tidyr); library(stringi) 

temp <- temp %>% 
  gather(new.Years, X, -Year) %>%  # convert rows to one column
  mutate(Year.temp=paste0(rownames(temp), "-", Year)) %>% # concatenate the Year with row number to make them unique
  mutate(new.Years = as.numeric(gsub("X", "", new.Years)), diff = new.Years-Year+1) %>% # calculate the difference to get the yr0 yr1 and so on
  mutate(diff=paste0("yr", stri_sub(paste0("0", (ifelse(diff>0, diff, 0))), -2, -1))) %>% # convert the differences in Yr01 ...
  select(-new.Years) %>% filter(diff != "yr00") %>% # drop new.Years column
  spread(diff, X) %>%  # convert column to rows
  select(-Year.temp) # Drop Year.temp column

temp[is.na(temp)] <- 0 # replace NA with 0

temp %>% View

请注意,这将工作长达 99 年。

【讨论】:

  • 您对简化数据的假设扭曲了它。每个案例都是唯一的,即使某些案例的“年份”变量具有相同的值(可能还有其他变量,例如不同年份的计数)。
【解决方案3】:

这是data.table 解决方案:

require(data.table)
require(reshape2)
dt.m = melt(dt, id = 1:2, variable.factor = FALSE)
dt.m[, variable := as.integer(variable)-Year+1L]
dcast.data.table(dt.m, case + Year ~ variable, fill=0L, 
      value.var = "value", subset = (variable > 0L))
#    case Year 1 2 3 4
# 1:    1 2003 0 3 0 0
# 2:    2 2002 5 3 2 0
# 3:    3 2001 3 3 2 2

【讨论】:

    【解决方案4】:
    library("devtools")
    df1 <- source_gist("b4c44aa67bfbcd6b72b9")$value
    

    我在列名中有一个 X 并将其删除:

    colnames(df1) <- gsub("X", "", colnames(df1))
    

    我有一个没有任何额外软件包的解决方案:

    startYear <- as.numeric(colnames(df1)[2])
    shifts <- df1$Year - startYear
    n <- ncol(df1)
    
    df2 <- df1
    colnames(df2)[-1] <- 1:(n-1) 
    df2[,2:n]  <- NA
    
    for(row in 1:nrow(df1)){
        if(shifts[row]>=0){
            df2[row,2:(n-shifts[row])] <- df1[row, (shifts[row]+2):n]
            #df2[row,2:(n-shifts[row])] <- colnames(df1)[(shifts[row]+2):n]
        }else{
            df2[row, (-shifts[row]+2):n] <- df1[row, 2:(n+shifts[row])]
            #df2[row, (-shifts[row]+2):n] <- colnames(df1)[2:(n+shifts[row])]
        }
    }
    

    您可以用0 代替NA 预填充df2。删除 ifelse 条件中的第二行并注释第一行以验证排列。

    希望它能如你所愿。

    【讨论】:

    • 这会产生 both NA 和 0?有什么区别?
    • 我不想在以前没有数据的地方生成数据。 NA 表示“不可用”,在 R 中没有数据的地方使用。但是您只需将第 7 行中的命令更改为 df2[,2:n] &lt;- 0,您只会得到 0。
    猜你喜欢
    • 2021-04-21
    • 2010-09-20
    • 1970-01-01
    • 1970-01-01
    • 2017-10-17
    • 2022-06-12
    • 2013-02-15
    • 2017-08-03
    • 1970-01-01
    相关资源
    最近更新 更多