2016-09-20 2 views
0

Я хочу построить матрицу или фрейм данных, выбирая имена столбцов, в которых содержится элемент в кадре данных, не содержит NA. Например, предположим, что у меня есть:Выберите имя столбца на основе содержимого фрейма данных R

zz <- data.frame(a = c(1, NA, 3, 5), 
        b = c(NA, 5, 4, NA), 
        c = c(5, 6, NA, 8)) 

, который дает:

a b c 
1 1 NA 5 
2 NA 5 6 
3 3 4 NA 
4 5 NA 8 

Я хочу признать каждый НС и построить новую матрицу или DF, которая выглядит как:

a c 
b c 
a b 
a c 

Там будет быть одинаковым числом NA в каждой строке входной матрицы/df. Кажется, я не могу получить правильный код. Предложения оценены!

+0

все строки имеют ровно 2 столбца, которые не являются 'NA'? – davechilders

+0

Да. Хороший вопрос. Представьте, что в этом вопросе. Да, в финальной матрице будет N столбцов, N = 2, а число NA в каждой строке будет одинаковым. – Ernie

ответ

3
library(dplyr) 
library(tidyr) 

zz %>% 
    mutate(k = row_number()) %>% 
    gather(column, value, a, b, c) %>% 
    filter(!is.na(value)) %>% 
    group_by(k) %>% 
    summarise(temp_var = paste(column, collapse = " ")) %>% 
    separate(temp_var, into = c("var1", "var2")) 

# A tibble: 4 × 3 
     k var1 var2 
* <int> <chr> <chr> 
1  1  a  c 
2  2  b  c 
3  3  a  b 
4  4  a  c 
+0

Это, безусловно, работает, но меня забирают в ящики с инструментами tidyr и dplyr, с которыми я еще не знаком. Благодарю. – Ernie

1

EDIT: транспонирование фрейм данных один раз, прежде чем процесс, так что не нужно дважды транспонировать в цикле в первой версии.

cols <- names(zz) 
for (column in cols) { 
    zz[[column]] <- ifelse(is.na(zz[[column]]), NA, column) 
} 
t_zz <- t(zz) 
cols <- vector("list", length = ncol(t_zz)) 
for (i in 1:ncol(t_zz)) { 
    cols[[i]] <- na.omit(t_zz[, i]) 
} 
new_dt <- as.data.frame(t(do.call("cbind", cols))) 

Хитрость здесь ваша цель на самом деле изменить структуру кадра данных, поэтому задача «удалить NA в каждой строке» должны строить построчно, как новый кадр данных, так как каждый столбец в каждой строке может пришел из другого столбца исходного кадра данных.

zz[1, ] - это рамка данных в одну строку, используйте t, чтобы преобразовать ее в вектор, чтобы мы могли использовать na.omit, а затем транспонировать обратно в строку.

Я использовал 2 для циклов, но для циклов не обязательно плохо в R. Первый векторизован для каждого столбца. В любом случае, второй должен выполняться по строкам.

EDIT: растущие объекты очень плохи в производительности в R. Я знал, что могу использовать rbindlist от data.table, который может взять список фреймов данных, но OP не хочет новых пакетов. Моя первая попытка просто использует rbind, который не смог взять список в качестве входных данных. Позже я нашел альтернативу использовать do.call. It's still slower than rbindlist though.

+0

Это очень плохой подход. Вы выполняете два для циклов, один за другим, пока растут объекты. Это противоречит всем основным правилам программирования в R –

+0

Не уверен, что я следую за ответом, new_dt, который для примера представляет собой 3X2 df со значениями столбца 1,2,3 и 3,2,6. Непонятно, как это дает мне желаемый ответ, который представляет собой матрицу 4X2 или df. – Ernie

+0

Растущие объекты плохие, я могу создать список фиксированных размеров, а затем rbindlist их вместе. Однако для этого потребуется 'data.table', а OP не хочет дополнительных пакетов. Я не уверен, есть ли другой метод привязки строк фрейма данных без растущего объекта. – dracodoc

3

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

indx <- which(!is.na(zz), arr.ind = TRUE) 
matrix(names(zz)[indx[order(indx[, "row"]), "col"]], ncol = 2, byrow = TRUE) 
# [,1] [,2] 
#[1,] "a" "c" 
#[2,] "b" "c" 
#[3,] "a" "b" 
#[4,] "a" "c" 

Это находит не-NA индексы, сортировка по строкам заказа, а затем подмножества имен ваших данных zz, установленных в соответствии с отсортированным индексом. Вы можете обернуть его в as.data.frame, если вы предпочитаете его по матрице.

+0

Дэвид очень приятный. Это компактное решение, которое позволяет избежать использования plyr и tidyr, и полезно, но требует какого-либо изучения, чтобы использовать его. – Ernie

Смежные вопросы