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