将字符串拆分为单个字母并记住位置

时间:2018-09-07 08:28:00

标签: r string split

我有一个像这样的数据集:

# 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), '')

我不知道应该如何将其转换为我的首选格式?

7 个答案:

答案 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
....

或使用

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创建。