Разделение столбца строки dataframe на несколько разных столбцов

то, что я пытаюсь сделать, это разделить столбец на несколько столбцов. Я бы предпочел, чтобы первый столбец содержал "F", второй столбец "US", третий "CA6" или "DL", а четвертый - "Z13" или "U13" и т. д. Весь мой df следует той же схеме X. XX.XXXX.XXX или X. XX.XXX.XXX или X. XX.XX.XXX и я знаю, что третья колонка-это моя проблема из-за разной длины. Я только использовал substr в прошлом, и я мог бы использовать это здесь с некоторыми утверждениями if, но хотел бы чтобы узнать, как использовать пакет stringr и POSIX для этого (если нет лучшего варианта). Заранее спасибо.

вот мой df:

c("F.US.CLE.V13", "F.US.CA6.U13", "F.US.CA6.U13", "F.US.CA6.U13", 
"F.US.CA6.U13", "F.US.CA6.U13", "F.US.CA6.U13", "F.US.CA6.U13", 
"F.US.DL.U13", "F.US.DL.U13", "F.US.DL.U13", "F.US.DL.Z13", "F.US.DL.Z13"
)

3 ответов


очень прямой способ-просто использовать read.table на вектор символов:

> read.table(text = text, sep = ".", colClasses = "character")
   V1 V2  V3  V4
1   F US CLE V13
2   F US CA6 U13
3   F US CA6 U13
4   F US CA6 U13
5   F US CA6 U13
6   F US CA6 U13
7   F US CA6 U13
8   F US CA6 U13
9   F US  DL U13
10  F US  DL U13
11  F US  DL U13
12  F US  DL Z13
13  F US  DL Z13

colClasses необходимо указать, в противном случае F преобразуется к виду FALSE (что мне нужно исправить в "splitstackshape", иначе я бы рекомендовал это :))


обновление (>год спустя)...

кроме того, вы можете использовать мой cSplit функции, например:

cSplit(as.data.table(text), "text", ".")
#     text_1 text_2 text_3 text_4
#  1:      F     US    CLE    V13
#  2:      F     US    CA6    U13
#  3:      F     US    CA6    U13
#  4:      F     US    CA6    U13
#  5:      F     US    CA6    U13
#  6:      F     US    CA6    U13
#  7:      F     US    CA6    U13
#  8:      F     US    CA6    U13
#  9:      F     US     DL    U13
# 10:      F     US     DL    U13
# 11:      F     US     DL    U13
# 12:      F     US     DL    Z13
# 13:      F     US     DL    Z13

или separate из "tidyr", как это:

library(dplyr)
library(tidyr)

as.data.frame(text) %>% separate(text, into = paste("V", 1:4, sep = "_"))
#    V_1 V_2 V_3 V_4
# 1    F  US CLE V13
# 2    F  US CA6 U13
# 3    F  US CA6 U13
# 4    F  US CA6 U13
# 5    F  US CA6 U13
# 6    F  US CA6 U13
# 7    F  US CA6 U13
# 8    F  US CA6 U13
# 9    F  US  DL U13
# 10   F  US  DL U13
# 11   F  US  DL U13
# 12   F  US  DL Z13
# 13   F  US  DL Z13

это то, что вы пытаетесь сделать?

# Our data
text <- c("F.US.CLE.V13", "F.US.CA6.U13", "F.US.CA6.U13", "F.US.CA6.U13", 
"F.US.CA6.U13", "F.US.CA6.U13", "F.US.CA6.U13", "F.US.CA6.U13", 
"F.US.DL.U13", "F.US.DL.U13", "F.US.DL.U13", "F.US.DL.Z13", "F.US.DL.Z13"
)

#  Split into individual elements by the '.' character
#  Remember to escape it, because '.' by itself matches any single character
elems <- unlist( strsplit( text , "\." ) )

#  We know the dataframe should have 4 columns, so make a matrix
m <- matrix( elems , ncol = 4 , byrow = TRUE )

#  Coerce to data.frame - head() is just to illustrate the top portion
head( as.data.frame( m ) )
#  V1 V2  V3  V4
#1  F US CLE V13
#2  F US CA6 U13
#3  F US CA6 U13
#4  F US CA6 U13
#5  F US CA6 U13
#6  F US CA6 U13

С помощью unlist и matrix кажется немного запутанным и требует от вас жесткого кода количества элементов (на самом деле это довольно большой запрет. Конечно, вы можете обойти жесткое кодирование этого числа и определить его во время выполнения)

Я бы пошел по другому пути, и создать фрейм данных непосредственно из списка, что strsplit возвращает. Для меня это концептуально проще. Существует два способа сделать это:

  1. as.data.frame - но так как список является совершенно неправильным (у нас есть список строк, а не список столбцов), мы должны транспонировать результат. Мы также очищаем rownames так как они уродливы по умолчанию (но это совершенно необязательно!):

    `rownames<-`(t(as.data.frame(strsplit(text, '\.'))), NULL)
    
  2. можно использовать rbind для построения фрейма данных из списка строк. Мы используем do.call называть rbind со всеми строками в качестве отдельных аргументов:

    do.call(rbind, strsplit(text, '\.'))
    

оба выхода путей тот же результат:

     [,1] [,2] [,3]  [,4]
[1,] "F"  "US" "CLE" "V13"
[2,] "F"  "US" "CA6" "U13"
[3,] "F"  "US" "CA6" "U13"
[4,] "F"  "US" "CA6" "U13"
[5,] "F"  "US" "CA6" "U13"
[6,] "F"  "US" "CA6" "U13"
…

очевидно, что второй способ намного проще, чем первый.