【发布时间】:2019-08-06 20:03:08
【问题描述】:
[还是新手,如果我需要提供更多信息来帮助解决我的问题,请告诉我]
试图帮助实验室成员进行一些数据分析,但数据中的列名混合了多个变量。
在他的数据中,每一行代表一个平均值。每列命名为 mean.x.y.z,其中 x、y 和 z 指的是不同变量的不同值。我们需要做的是将每个列名拆分为其复合部分,并为每个部分创建单独的列。
举个更具体的例子,如果这是我们提供的数据:
messy <- tibble(
id = c('P1', 'P2', 'P3'),
value.neutral.up = c(1.2, 1.3, 1.2),
value.neutral.down = c(2.1, 3.1, 2.1),
value.valid.up = c(1.2, 1.3, 1.2),
value.valid.down = c(2.1, 3.1, 2.1),
value.invalid.up = c(1.2, 1.3, 1.2),
value.invalid.down = c(2.1, 3.1, 2.1)
)
messy
# A tibble: 3 x 7
id value.neutral.up value.neutral.down value.valid.up value.valid.down value.invalid.up value.invalid.down
<chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 P1 1.2 2.1 1.2 2.1 1.2 2.1
2 P2 1.3 3.1 1.3 3.1 1.3 3.1
3 P3 1.2 2.1 1.2 2.1 1.2 2.1
Value 是指我们要提取的数值,neutral/valid/invalid & up/down 是指两个预测变量的水平。
考虑到这一点,我们的最终目标如下所示:
tidy <- tibble(
id = c( rep('P1', 6), rep('P2', 6), rep('P3', 6)),
cue = rep(c('neutral', 'valid', 'invalid'),6),
direction = rep(c('up', 'down'), 9),
value = rep(c(1.2, 1.3, 1.4, 2.1, 3.1, 4.1), 3)
)
tidy
# A tibble: 18 x 4
id cue direction value
<chr> <chr> <chr> <dbl>
1 P1 neutral up 1.2
2 P1 valid down 1.3
3 P1 invalid up 1.4
4 P1 neutral down 2.1
5 P1 valid up 3.1
6 P1 invalid down 4.1
7 P2 neutral up 1.2
8 P2 valid down 1.3
9 P2 invalid up 1.4
10 P2 neutral down 2.1
11 P2 valid up 3.1
12 P2 invalid down 4.1
13 P3 neutral up 1.2
14 P3 valid down 1.3
15 P3 invalid up 1.4
16 P3 neutral down 2.1
17 P3 valid up 3.1
18 P3 invalid down 4.1
我以前使用过 reshape2::gather() 来解决这类问题,但仅限于列名没有复合多个变量名的情况。也就是说,如果列是 value.neutral、value.valid 等,那很好,但我不知道如何处理额外的 .up/down 位。
关于如何处理这个问题的任何建议?即使有人可以帮助我更好地表达这个问题(用可搜索的术语),我也会很感激。
谢谢各位!
【问题讨论】:
-
试试
messy %>% gather(key,value,-id) %>% separate(key, into = c('val','cue','dir')) %>% select(-val),注意可能会被标记为dup。 -
既然我理解了解决方案,肯定是重复的。
-
我在您链接到的帖子中没有看到的后续问题:虽然我的大多数专栏都有 3 个部分名称,但有些有四个。有没有办法单独使用来解决这个问题?或者将它们放在另一个数据框中,调整并重新插入会更容易吗?我不介意做后者,但我想看看是否有更清洁/更简洁的方式。
-
我们可以改编来自here 的Gregor 的回答。使用
messy %>% gather(key,value,-id) -> messy1;maxchar = max(stringr::str_count(messy1$key, pattern = '\\.'))定义maxchar然后执行tidyr::separate(messy1, key, into = paste0("key", 1:(maxchar+1)), sep = '\\.') -
谢谢朋友。如果对列的命名方式有一定的一致性,这将是开箱即用的,但这是一个可靠的开始,对未来很有用。