Заполните пустые значения данными из следующих столбцов - PullRequest
0 голосов
/ 19 февраля 2020

Имея такой фрейм данных:

data.frame(id = c(1,2,3,4), text1 = c("sth","","another",""), text2 = c("more","another","add",""), text3 = c("final","and","where","all"))

Как можно определить, является ли строка в столбце text1 пустой, заполнить ее значением, существующим в столбце text2, text3 или text4, и оставить из этого NA после процесса

Пример ожидаемого результата

data.frame(id = c(1,2,3,4), text1 = c("sth","another","another","all"), text2 = c("more","","add",""), text3 = c("final","and","where",""))

Ответы [ 6 ]

2 голосов
/ 19 февраля 2020

Векторизованный базовый подход R:

#Get indices where text1 is empty
inds <- which(df$text1 == '')
#get values to replace from the corresponding rows
vals <- cbind(inds, max.col(df[inds, 3:ncol(df)] != "") + 2)
#Replace the values    
df$text1[inds] <- df[vals]
#Change the replaced value with blank.
df[vals] <- ''

df
#  id   text1 text2 text3
#1  1     sth  more final
#2  2 another         and
#3  3 another   add where
#4  4     all            

данные

df <- data.frame(id = c(1,2,3,4), text1 = c("sth","","another",""), 
       text2 = c("more","another","add",""), 
       text3 = c("final","and","where","all"), stringsAsFactors = FALSE)
1 голос
/ 19 февраля 2020

На этом этапе, почему бы не использовать подход dplyr? По общему признанию, с блеском базы R в середине

df <- data.frame(id = c(1,2,3,4),
                 text1 = c("sth","","another",""),
                 text2 = c("more","another","add",""),
                 text3 = c("final","and","where","all"))

library("dplyr")
library("tidyr")

df_filled <- df %>%
    pivot_longer(cols = starts_with("text"),
                 names_to = "text_id",
                 values_to = "value") %>%
    mutate(value = as.character(value)) %>%
    group_by(id) %>%
    mutate(value = if_else(value=="", as.character(NA), value)) %>%
    mutate(previously_missing = value) %>%
    tidyr::fill(value, .direction = "downup")

df_filled$value[which(is.na(df_filled$previously_missing)&df_filled$text_id!="text3")+1] <- NA

df_filled %>%
    ungroup() %>%
    pivot_wider(id_cols = id,
                names_from = "text_id",
                values_from = "value")
#> # A tibble: 4 x 4
#>      id text1   text2 text3
#>   <dbl> <chr>   <chr> <chr>
#> 1     1 sth     more  final
#> 2     2 another <NA>  and  
#> 3     3 another add   where
#> 4     4 all     <NA>  <NA>

Создано в 2020-02-19 с помощью пакета представительства (v0.3.0)

1 голос
/ 19 февраля 2020

Вы можете использовать dplyr + purrr:

df %>% 
 tidyr::nest(-id) %>% 
 dplyr::mutate(
    new_text = purrr::map_chr(
    data, ~ 
       as.vector(t(.x[1,])) %>% 
         .[. != ""] %>% 
         dplyr::first())) %>% 
  tidyr::unnest()

 A tibble: 4 x 5
     id text1   text2   text3 new_text
  <dbl> <fct>   <fct>   <fct> <chr>   
1     1 sth     more    final sth     
2     2 ""      another and   another 
3     3 another add     where another 
4     4 ""      ""      all   all  
1 голос
/ 19 февраля 2020

здесь data.table подход ...

объяснение в комментариях ниже

#sample data
df <- data.frame(id = c(1,2,3,4), text1 = c("sth","","another",""), text2 = c("more","another","add",""), text3 = c("final","and","where","all"), stringsAsFactors = FALSE)

library( data.table )
#create data.table
setDT( df )
#paste together columns by id
ans <- df[, .(string = paste0( .SD, collapse =";")), by = .(id) ][]
#    id            string
# 1:  1    sth;more;final
# 2:  2      ;another;and
# 3:  3 another;add;where
# 4:  4             ;;all

#remove leading;'s
ans[, string := gsub("^;+", "", string) ]
#    id            string
# 1:  1    sth;more;final
# 2:  2       another;and
# 3:  3 another;add;where
# 4:  4               all

#split string back to columns, remove the temporary string-column
ans[, paste0( "text", 1:length( tstrsplit(ans$string, ";") ) ) := 
      tstrsplit( string, ";") ][, string := NULL ]
#    id   text1 text2 text3
# 1:  1     sth  more final
# 2:  2 another   and  <NA>
# 3:  3 another   add where
# 4:  4     all  <NA>  <NA>
1 голос
/ 19 февраля 2020

В базе R вы можете сделать:

txt <- do.call(paste,c(sep = ',',`is.na<-`(df,df=="")))
df1 <- read.csv(text = sub("((?:,NA)+)(,\\w+)","\\2\\1",txt),
               header = FALSE, 
               col.names = names(df),
               stringsAsFactors = FALSE)

df1[is.na(df1)] <- ""
df1
  id   text1 text2 text3
1  1     sth  more final
2  2 another         and
3  3 another   add where
4  4     all            
0 голосов
/ 19 февраля 2020

Другое базовое решение R состоит в том, чтобы определить вашу пользовательскую функцию swap и применить ее по строкам, т. Е.

swap <- function(v) {v[inds]<-v[rev(inds <- c(1,head(which(nchar(v)>0),1)))];v}
df[-1]<-t(apply(df[-1], 1, swap))

так, чтобы

> df
  id   text1 text2 text3
1  1     sth  more final
2  2 another         and
3  3 another   add where
4  4     all 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...