问题
I'm trying to use tidyr to separate one column in my data frame, while applying it only to specific rows. While dplyr::filter does the job, it omits the rest of my data. Is there a clean way to apply tidyr to specific rows while keeping the rest of the data untouched?
here is an example of my problem:
#creating DF for the example
df<-data.frame(var_a=letters[1:5],
var_b=c(sample(1:100,5)),
text=c("foo_bla","here_do","oh_yes","baa","land"))
gives me this:
var_a var_b text 1 a 10 foo_bla 2 b 58 here_do 3 c 34 oh_yes 4 d 1 baa 5 e 47 land
#separating one col:
clean_df<-df %>% separate(text,into=c("first","sec"),sep="_",remove=F)
clean_df
var_a var_b text first sec 1 a 10 foo_bla foo bla 2 b 58 here_do here do 3 c 34 oh_yes oh yes 4 d 1 baa baa <NA> 5 e 47 land land <NA>
I want to split only the "here_do" row. Thanks in advance for any kind of help!
回答1:
Another approach:
cols_to_split = c('here_do')
clean_df <-df %>%
filter(text %in% cols_to_split) %>%
tidyr::separate(text,into=c("first","sec"),sep="_",remove=F) %>%
bind_rows(filter(df, !text %in% cols_to_split))
# var_a var_b text first sec
#1 b 7 here_do here do
#2 a 26 foo_bla <NA> <NA>
#3 c 23 oh_yes <NA> <NA>
#4 d 2 baa <NA> <NA>
#5 e 67 land <NA> <NA>
If you need to keep rest of the rows in column 'first', you may use:
clean_df <-df %>%
filter(text %in% cols_to_split) %>%
tidyr::separate(text,into=c("first","sec"),sep="_",remove=F) %>%
bind_rows(filter(df, !text %in% cols_to_split)) %>%
mutate(first = ifelse(is.na(first), as.character(text), first))
# var_a var_b text first sec
#1 b 7 here_do here do
#2 a 26 foo_bla foo_bla <NA>
#3 c 23 oh_yes oh_yes <NA>
#4 d 2 baa baa <NA>
#5 e 67 land land <NA>
回答2:
We can do this in base R
by replacing the delimiter for the 'here_do' in the 'text' column i.e. change it to 'here,do' using sub
, read it with read.csv
and cbind
with the original dataset
cbind(df, read.csv(text=sub("(?<=here)_(?=do)", ",", df$text,
perl = TRUE), header=FALSE, col.names = c("first", "sec")))
# var_a var_b text first sec
#1 a 93 foo_bla foo_bla
#2 b 51 here_do here do
#3 c 65 oh_yes oh_yes
#4 d 70 baa baa
#5 e 32 land land
Or if we need a tidyr
solution, use the extract
library(tidyr)
extract(df, text, into = c("first", "sec"), "(here)_(do)", remove = FALSE)
# var_a var_b text first sec
#1 a 93 foo_bla <NA> <NA>
#2 b 51 here_do here do
#3 c 65 oh_yes <NA> <NA>
#4 d 70 baa <NA> <NA>
#5 e 32 land <NA> <NA>
来源:https://stackoverflow.com/questions/41506310/applying-tidyr-separate-only-to-specific-rows