Разделение столбца строки 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"
)
Ответы
Ответ 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"
…
Очевидно, что второй способ намного проще первого.