/ / Як я можу розділити рядок символів у кадрі даних на декілька стовпців - r, string, split

Як я можу розділити рядок символів на кадр даних на кілька стовпчиків - r, рядок, розділити

Я працюю з кадру даних, один стовпчик якогомістить значення, які в основному числові, але можуть містити нечислові записи. Я хотів би розділити цей стовпець на кілька стовпців. Один з нових стовпців повинен містити числову частину вихідного запису, а інша колонка повинна містити будь-які нечислові елементи.

Ось приклад кадру даних:

df <- data.frame(ID=1:4,x=c("< 0.1","100","A 2.5", "200"))

Ось що я хотів би, щоб кадр даних виглядав так:

ID   x1   x2
1    <    0.1
2         100
3    A    2.5
4         200

Про особливості даних, які я зараз беруПеревагою є те, що структура рядків символів завжди така: не числові елементи (якщо вони існують) завжди передують числовим елементам, і два елементи завжди розділені пропуском.

Я можу використовувати colsplit з пакета reshape, щоб розділити стовпець на основі пробілу. Проблема з цим полягає в тому, що вона реплікує будь-який запис, який не може бути розділений на два елементи,

require(reshape)
df <- transform(df, x=colsplit(x,split=" ", names("x1","x2")))
df
ID  x1   x2
1   <    0.1
2   100  100
3   A    2.5
4   200  200

Це не дуже проблематично, оскільки я можу просто зробити деякі постобробки для видалення числових елементів з стовпця "x1".

Я також можу виконати те, що я хотів би зробити за допомогою strsplit всередині функції:

split.fn <- function(id){
new.val <- unlist(strsplit(as.character(df$x[df$ID==id])," "))
if(length(new.val)==1){
return(data.frame(ID=id,x1="NA",x2=new.val))
}else{
return(data.frame(ID=id,x1=new.val[1],x2=new.val[2]))
}

}
data.frame(rbindlist(lapply(unique(df$ID),split.fn)))
ID   x1   x2
1    <    0.1
2    NA   100
3    A    2.5
4    NA   200

але це здається громіздким.

В основному обидва варіанти, які я описав тут, будуть працювати. Але я підозрюю, що є більш елегантний або прямий спосіб отримати потрібний кадр даних.

Відповіді:

5 за відповідь № 1

Ви можете використовувати separate() від тидир

tidyr::separate(df, x, c("x1", "x2"), " ", fill = "left")
#   ID   x1  x2
# 1  1    < 0.1
# 2  2 <NA> 100
# 3  3    A 2.5
# 4  4 <NA> 200

Якщо вам абсолютно необхідно видалити NA значення, тоді можна зробити

tdy <- tidyr::separate(df, x, c("x1", "x2"), " ", fill = "left")
tdy[is.na(tdy)] <- ""

і тоді у нас є

tdy
#   ID x1  x2
# 1  1  < 0.1
# 2  2    100
# 3  3  A 2.5
# 4  4    200

1 для відповіді № 2

Не використовуються пакети:

transform(df,
x1 = ifelse(grepl(" ", x), sub(" .*", "", x), NA),
x2 = sub(".* ", "", paste(x)))

даючи:

  ID     x   x1  x2
1  1 < 0.1    < 0.1
2  2   100 <NA> 100
3  3 A 2.5    A 2.5
4  4   200 <NA> 200