【问题标题】:Pivot/Reshape data in R [duplicate]R中的数据透视/重塑数据[重复]
【发布时间】:2020-09-14 11:02:17
【问题描述】:

谢谢大家的回答,我以为我比我聪明,希望我能理解其中的任何一个。我想我也搞砸了我的数据可视化。我已经编辑了我的帖子以更好地显示我的示例数据。很抱歉给您带来不便,我真的希望有人可以帮助我。

我有一个关于重塑数据的问题。收集的数据如下所示:

 data <- read.table(header=T, text='
  pid     measurement1     Tdays1     measurement2      Tdays2     measurement3     Tdays3  measurment4    Tdays4 
   1         1356           1435         1483            1405         1563           1374       NA           NA     
   2         943            1848         1173            1818         1300           1785       NA           NA     
   3         1590           185          NA              NA           NA             NA         1585         294    
   4         130            72           443             70           NA             NA         136          79     
   4         140            82           NA              NA           NA             NA         756          89     
   4         220            126          266             124          NA             NA         703          128    
   4         166            159          213             156          476            145        776          166    
   4         380            189          583             173          NA             NA         586          203    
   4         353            231          510             222          656            217        526          240    
   4         180            268          NA              NA           NA             NA         NA           NA       
   4         NA             NA           NA              NA           NA             NA         580          278    
   4         571            334          596             303          816            289        483          371    
  ')

现在我希望它看起来像这样:

PID     Time   Value
 1       1435   1356
 1       1405   1483
 1       1374   1563
 2       1848   943
 2       1818   1173
 2       1785   1300
 3       185    1590
...     ...     ... 

我将如何到达那里?我已经查找了一些关于宽格式到长格式的内容,但它似乎没有奏效。我对 Rstudio 和 Stackoverflow 相对陌生(如果你还不能说的话)。

诚挚的问候,并在此先感谢您。

【问题讨论】:

标签: r reshape


【解决方案1】:

这是一个略有不同的pivot_longer() 版本。

library(tidyr)
library(dplyr)
dw %>% 
  pivot_longer(cols = -PID, names_to =".value", names_pattern = "(.+)[0-9]")
# A tibble: 9 x 3
    PID     T measurement
  <dbl> <dbl>       <dbl>
1     1     1         100
2     1     4         200
3     1     7          50
4     2     2         150
5     2     5         300
6     2     8          60
7     3     3         120
8     3     6         210
9     3     9          70

names_to = ".value" 参数基于 names_pattern 参数从列名创建新列。 names_pattern 参数采用特殊的正则表达式输入。在这种情况下,以下是细分:

(.+)  # match everything - anything noted like this becomes the ".values"
[0-9] # numeric characters - tells the pattern that the numbers 
      # at the end are excluded from ".values". If you have multiple digit 
      # numbers, use [0-9*]

【讨论】:

    【解决方案2】:

    在上一次编辑中,您要求提供易于理解的解决方案。一种非常简单的方法是将测量列堆叠在一起,将 Tdays 列堆叠在一起。虽然专业包让事情变得非常简洁和优雅,但为了简单起见,我们可以在不额外包的情况下解决这个问题。标准 R 有一个方便的函数,恰如其分地命名为 stack,它的工作原理如下:

    > exp <-  data.frame(value1 = 1:5, value2 = 6:10)
    > stack(exp)
       values    ind
    1       1 value1
    2       2 value1
    3       3 value1
    4       4 value1
    5       5 value1
    6       6 value2
    7       7 value2
    8       8 value2
    9       9 value2
    10     10 value2
    

    我们可以将测量值和 Tdays 分开叠加,然后通过cbind 将它们组合起来:

    data <- read.table(header=T, text='
      pid     measurement1     Tdays1     measurement2      Tdays2     measurement3     Tdays3  measurement4    Tdays4 
       1         1356           1435         1483            1405         1563           1374       NA           NA     
       2         943            1848         1173            1818         1300           1785       NA           NA     
       3         1590           185          NA              NA           NA             NA         1585         294    
       4         130            72           443             70           NA             NA         136          79     
       4         140            82           NA              NA           NA             NA         756          89     
       4         220            126          266             124          NA             NA         703          128    
       4         166            159          213             156          476            145        776          166    
       4         380            189          583             173          NA             NA         586          203    
       4         353            231          510             222          656            217        526          240    
       4         180            268          NA              NA           NA             NA         NA           NA       
       4         NA             NA           NA              NA           NA             NA         580          278    
       4         571            334          596             303          816            289        483          371    
      ')
    
    
    cbind(stack(data, c(measurement1, measurement2, measurement3, measurement4)),
          stack(data, c(Tdays1, Tdays2, Tdays3, Tdays4)))
    

    这将测量值和 Tdays 整齐地放在一起,但让我们没有 pid,我们可以使用 rep 添加以复制原始 pid 4 次:

    result <- cbind(pid = rep(data$pid, 4),
                    stack(data, c(measurement1, measurement2, measurement3, measurement4)),
                    stack(data, c(Tdays1, Tdays2, Tdays3, Tdays4)))
    

    它的头看起来像

    > head(result)
      pid values          ind values    ind
    1   1   1356 measurement1   1435 Tdays1
    2   2    943 measurement1   1848 Tdays1
    3   3   1590 measurement1    185 Tdays1
    4   4    130 measurement1     72 Tdays1
    5   4    140 measurement1     82 Tdays1
    6   4    220 measurement1    126 Tdays1
    

    正如我上面所说,这不是您期望的顺序,如果有任何问题,您可以尝试对此 data.frame 进行排序:

    result <- result[order(result$pid), c(1, 4, 2)]
    names(result) <- c("pid", "Time", "Value")
    

    导致最终结果

    > head(result)
       pid Time Value
    1    1 1435  1356
    13   1 1405  1483
    25   1 1374  1563
    37   1   NA    NA
    2    2 1848   943
    14   2 1818  1173
    

    【讨论】:

    • 非常感谢您,先生!这成功了!
    【解决方案3】:

    tidyverse解决方案

    library(tidyverse)
    dw %>% 
      pivot_longer(-PID) %>% 
      mutate(name = gsub('^([A-Za-z]+)(\\d+)$', '\\1_\\2', name )) %>% 
      separate(name, into = c('A', 'B'), sep = '_', convert = T) %>% 
      pivot_wider(names_from = A, values_from = value)
    

    给出以下输出

    # A tibble: 9 x 4
        PID     B     T measurement
      <int> <int> <int>       <int>
    1     1     1     1         100
    2     1     2     4         200
    3     1     3     7          50
    4     2     1     2         150
    5     2     2     5         300
    6     2     3     8          60
    7     3     1     3         120
    8     3     2     6         210
    9     3     3     9          70
    

    【讨论】:

      【解决方案4】:

      考虑一个数据框,df 如下:

           PID T1 measurement1 T2 measurement2 T3 measurement3
           1   1          100  4          200  7           50
           2   2          150  5          300  8           60
           3   3          120  6          210  9           70
      

      您可以使用此解决方案来获取所需的数据框:

      iters = seq(from = 4, to = length(colnames(df))-1, by = 2)
      finalDf = df[, c(1,2,3)]
      for(j in iters){
          tobind = df[, c(1,j,j+1)]
          finalDf = rbind(finalDf, tobind)
      }
      
      finalDf = finalDf[order(finalDf[,1]),]
      
      print(finalDf)
      

      print 语句的输出是这样的:

         PID T1 measurement1
      1   1  1          100
      4   1  4          200
      7   1  7           50
      2   2  2          150
      5   2  5          300
      8   2  8           60
      3   3  3          120
      6   3  6          210
      9   3  9           70
      

      【讨论】:

      • 在原twT1 == 4PID == 2相关联。在您的结果中,T1 == 4PID == 1 相关联。是不是错了?
      • 好的,让我再检查一下.. 排序的一些问题
      • 我错误地粘贴了错误的输出。代码工作正常,只是检查并更新了输出。
      • 您上次的编辑更改了行号,而不是输出的 PID 列。到目前为止,我的上述评论没有任何改变。
      • 这是因为我考虑了一个相似但不同的数据框,而不是问题中给出的数据框,请正确查看解决方案。它一定会给出这个输出,因此不需要更改。
      【解决方案5】:

      也许你可以试试下面的reshape

      reshape(
        setNames(data, gsub("(\\d+)$", "\\.\\1", names(data))),
        direction = "long",
        varying = 2:ncol(data)
      )
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-11-09
        • 2017-04-05
        • 2010-12-04
        • 2015-08-04
        • 1970-01-01
        • 2017-09-06
        • 2013-04-20
        • 1970-01-01
        相关资源
        最近更新 更多