问题描述
谢谢大家的回答,我以为自己比以前聪明,希望我能理解其中的任何一个。我想我也弄乱了我的数据可视化。我已经编辑了帖子,以更好地显示示例数据。很抱歉给您带来不便,我真的希望有人能帮助我。
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的新功能(如果您还不能确定的话)。
致以问候,谢谢。
解决方法
这里的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*]
,
考虑数据帧,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[,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
,
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
,
在上一次编辑中,您要求一个易于理解的解决方案。一种非常简单的方法是将测量列彼此堆叠,而将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
我们可以分别堆叠测量值和Tday,然后通过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)))
哪些可以将测量值和Tday整齐地保持在一起,但没有pid
,我们可以使用rep
将其添加到原始pid
中,将其复制4次:
result <- cbind(pid = rep(data$pid,4),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),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
,
也许您可以像下面那样尝试text
reshape