Самый эффективный способ объединить строковые столбцы и пропустить отдельные поля - PullRequest
0 голосов
/ 06 сентября 2018

Я постараюсь упростить мою df:

Animal1  Animal2  Animal3
dog      cat      mouse
dog      0        mouse
0        cat      0

только с 3 записями.

Я хочу объединить всех 3 животных в одно поле, где он будет выглядеть следующим образом:

Animals
dog + cat + mouse
dog + mouse
cat

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

Обратите внимание, что это нужно сделать примерно для 10 миллионов строк.

Ответы [ 3 ]

0 голосов
/ 06 сентября 2018

1) Использование DF, воспроизводимого в примечании в конце, определяет функцию Collapse, которая принимает символьный вектор, удаляет элементы «0» и объединяет остальные в строку, разделенную знаки плюс. Используйте apply, чтобы применить это к каждой строке.

Collapse = function(x) paste(x[x != 0], collapse = "+")
transform(DF, Animals = apply(DF, 1, Collapse))

дает:

  Animal1 Animal2 Animal3       Animals
1     dog     cat   mouse dog+cat+mouse
2     dog       0   mouse     dog+mouse
3       0     cat       0           cat

2) В качестве альтернативы, если запятая с последующим пробелом подходит в качестве разделителя, используйте это для Collapse:

Collapse <- function(x) toString(x[x != 0])

, который при использовании с оператором transform в (1) дает:

  Animal1 Animal2 Animal3         Animals
1     dog     cat   mouse dog, cat, mouse
2     dog       0   mouse      dog, mouse
3       0     cat       0             cat

3) Другая возможность - сделать столбец Animals списком векторов:

DF2 <- DF
DF2$Animals <- lapply(split(DF, 1:nrow(DF)), function(x) x[x != 0])

дает:

> DF2
  Animal1 Animal2 Animal3         Animals
1     dog     cat   mouse dog, cat, mouse
2     dog       0   mouse      dog, mouse
3       0     cat       0             cat

> str(DF2)
'data.frame':   3 obs. of  4 variables:
 $ Animal1: chr  "dog" "dog" "0"
 $ Animal2: chr  "cat" "0" "cat"
 $ Animal3: chr  "mouse" "mouse" "0"
 $ Animals:List of 3
  ..$ 1: chr  "dog" "cat" "mouse"
  ..$ 2: chr  "dog" "mouse"
  ..$ 3: chr "cat"

Примечание

Lines <- "Animal1  Animal2  Animal3
dog      cat      mouse
dog      0        mouse
0        cat      0"
DF <- read.table(text = Lines, header = TRUE, as.is = TRUE)
0 голосов
/ 07 сентября 2018

Другая идея:

library(tidyverse)

df2 %>%
  na_if(0) %>%
  mutate(Animals = pmap_chr(., .f = ~stringi::stri_flatten(
    c(...), collapse = " + ", 
    na_empty = TRUE, omit_empty = TRUE)))

Что дает:

#  Animal1 Animal2 Animal3           Animals
#1    <NA>    <NA>   mouse             mouse
#2     dog     cat   mouse dog + cat + mouse
#3     dog    <NA>   mouse       dog + mouse
#4    <NA>     cat    <NA>               cat
#5    <NA>    <NA>    <NA>                  

Данные

df2 <- data.frame(
  Animal1 = c("0", "dog", "dog", "0", "0"), 
  Animal2 = c("0", "cat", "0", "cat","0"), 
  Animal3 = c("mouse", "mouse", "mouse", "0","0"),
  stringsAsFactors = FALSE)
0 голосов
/ 06 сентября 2018

Вы можете использовать вложенную функцию sub, чтобы получить желаемый результат:

df <- data.frame(Animal1 = c("dog", "dog", "0"), 
                 Animal2 = c("cat", "0", "cat"), 
                 Animal3 = c("mouse", "mouse", "0"))

df$Animals <- sub("\\+ 0", "", sub("0 \\+", "", paste(df$Animal1, df$Animal2, df$Animal3, sep = " + ")))
...