Подтвердить что ты не робот

Разделение столбца строки 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"
)
4b9b3361

Ответ 1

Очень прямой способ - просто использовать 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", иначе я бы рекомендовал:))


Обновление ( > через год)...

В качестве альтернативы вы можете использовать my 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

Ответ 2

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

# 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

Ответ 3

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

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

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

    `rownames<-`(t(as.data.frame(strsplit(text, '\\.'))), NULL)
    
  • В качестве альтернативы используйте 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"
…

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