我有一个像这样的数据集:
# test data
test.table <- data.frame(
id = seq(1,3),
sequence = c('HELLOTHISISASTRING','STRING|IS||18|LONG','SOMEOTHERSTRING!!!')
)
每个序列具有相同的长度(18)。现在,我要创建一个像这样的表:
#id position letter
#1 1 H
#1 2 E
#1 3 L
#.....etc
尽管我知道我可以使用strsplit
分割字符串,例如:
splitted <- strsplit(as.character(test.table$sequence), '')
我不知道应该如何将其转换为我的首选格式?
答案 0 :(得分:1)
您可以使用tidyverse
工具:
test.table <- data.frame(
id = seq(1,3),
sequence = c('HELLOTHISISASTRING','STRING|IS||18|LONG','SOMEOTHERSTRING!!!')
)
library(tidyverse)
test.table %>%
mutate(letters = str_split(sequence, "")) %>%
unnest %>%
group_by(id, sequence) %>%
mutate(position = row_number())
#> # A tibble: 54 x 4
#> # Groups: id, sequence [3]
#> id sequence letters position
#> <int> <fct> <chr> <int>
#> 1 1 HELLOTHISISASTRING H 1
#> 2 1 HELLOTHISISASTRING E 2
#> 3 1 HELLOTHISISASTRING L 3
#> 4 1 HELLOTHISISASTRING L 4
#> 5 1 HELLOTHISISASTRING O 5
#> 6 1 HELLOTHISISASTRING T 6
#> 7 1 HELLOTHISISASTRING H 7
#> 8 1 HELLOTHISISASTRING I 8
#> 9 1 HELLOTHISISASTRING S 9
#> 10 1 HELLOTHISISASTRING I 10
#> # ... with 44 more rows
由reprex package(v0.2.0)于2018-09-07创建。
答案 1 :(得分:1)
基本的R解决方案:
df <- stack(setNames(strsplit(as.character(test.table$sequence), ""), test.table$id))[2:1]
df$pos <- with(df, ave(values, ind, FUN = seq_along))
给出:
> df ind values pos 1 1 H 1 2 1 E 2 3 1 L 3 4 1 L 4 5 1 O 5 6 1 T 6 7 1 H 7 8 1 I 8 ....
或使用data.table:
library(data.table)
setDT(test.table)
test.table[, .(letter = unlist(tstrsplit(sequence, "", fixed=TRUE))), id
][, pos := rowid(id)][]
给出相同的结果:
id letter pos 1: 1 H 1 2: 1 E 2 3: 1 L 3 4: 1 L 4 5: 1 O 5 6: 1 T 6 7: 1 H 7 8: 1 I 8 ....
答案 2 :(得分:1)
有一个方便的软件包,涉及诸如splitstackshape
之类的操作。
library(splitstackshape)
dt1 <- cSplit(test.table, 'sequence', sep = '', direction = 'long', stripWhite = FALSE)
dt1$pos <- seq(18)
给出,
id sequence pos 1: 1 H 1 2: 1 E 2 3: 1 L 3 4: 1 L 4 5: 1 O 5 6: 1 T 6 7: 1 H 7 8: 1 I 8 9: 1 S 9 10: 1 I 10 ...
答案 3 :(得分:0)
使用stringi
软件包尝试此操作:
library(stringi)
data=data.frame()
for(i in 1:nrow(test.table)){ # For each id
# Split the data for each index and store the itermediate result and
# bind it as id, position and letter
df=cbind(test.table$id[i],1: stri_length(test.table$sequence[i]),stri_sub(test.table$sequence[i],
seq(1, stri_length(test.table$sequence[i]),by=1), length=1))
data=rbind(data,df) # Append each id result to data
}
colnames(data)=c('id','position','letter')
输出:
id position letter
1 1 1 H
2 1 2 E
3 1 3 L
4 1 4 L
5 1 5 O
6 1 6 T
答案 4 :(得分:0)
这里已经有一些不错的答案,但这是使用tidyverse
的另一种方法。
test.table <- data.frame(
id = seq(1,3),
sequence = c('HELLOTHISISASTRING','STRING|IS||18|LONG','SOMEOTHERSTRING!!!')
)
library(tidyverse)
library(reshape2)
test.table %>%
separate(col=sequence, into=as.character(1:18), sep=1:17) %>%
melt('id', value.name = 'letter', variable.name='position') %>%
arrange(id, position)
在上面的代码中,separate
中的tidyr
函数将sequence
列分成18个单独的列(将它们命名为1到18),然后将它们融为{{1 }}和letter
列。
答案 5 :(得分:0)
答案不是按照要求的,但是根据您的评论进行猜测,我们可能需要它:
chartr("HES", "ZXY", test.table$sequence)
# [1] "ZXLLOTZIYIYAYTRING" "YTRING|IY||18|LONG" "YOMXOTZXRYTRING!!!"
我们将每个H替换为Z,将E替换为X,将S替换为Y,等等。
答案 6 :(得分:0)
这是主题的另一种变化。
library(tidyverse)
test.table %>%
nest(-id) %>%
mutate(letters = map(data, ~str_split(.x$sequence,'') %>% unlist()),
numbers = map(letters, ~1:length(.x))) %>%
unnest(letters, numbers)
#> # A tibble: 54 x 3
#> id letters numbers
#> <int> <chr> <int>
#> 1 1 H 1
#> 2 1 E 2
#> 3 1 L 3
#> 4 1 L 4
#> 5 1 O 5
#> 6 1 T 6
#> 7 1 H 7
#> 8 1 I 8
#> 9 1 S 9
#> 10 1 I 10
#> # ... with 44 more rows
或略有不同,以避免两次调用地图
test.table %>%
nest(-id) %>%
mutate(newdata = map(data, ~data_frame(
letters = str_split(.x$sequence, "") %>% unlist(),
numbers = 1:str_count(.x$sequence)))) %>%
unnest(newdata)
#> # A tibble: 54 x 3
#> id letters numbers
#> <int> <chr> <int>
#> 1 1 H 1
#> 2 1 E 2
#> 3 1 L 3
#> 4 1 L 4
#> 5 1 O 5
#> 6 1 T 6
#> 7 1 H 7
#> 8 1 I 8
#> 9 1 S 9
#> 10 1 I 10
#> # ... with 44 more rows
由reprex package(v0.2.0)于2018-09-07创建。