как перемещать строки вверх и вниз и удалять из них похожие?

Я задал вопрос, который, вероятно, был не так ясен. поэтому постараюсь объяснить доступно. это мои данные

Мои данные выглядят так

Это выглядит так

#             V1      V2               V3
#1                 Q9UNZ5             Q9Y2W1
#2 Q9ULV4;Q6QEF8                     
#3                                    Q9UNZ5
#4                  Q9H6F5              
#5                  Q9H2K0     Q9ULV4;Q6QEF8
#6                  Q9GZZ1            Q9UKD2
#7        Q9H6F5    Q9GZZ1            Q9GZZ1
#8        Q9GZZ1                      Q9NYF8
#9        Q9BWS9                     

Я хочу удалить повторяющиеся строки во всех из них, например, V1, у нас есть все строки в первый раз, поэтому мы ничего не удаляем, просто упорядочиваем их.

Q9ULV4
Q6QEF8
Q9H6F5
Q9GZZ1 
Q9BWS9

Затем мы сверяем строки второго столбца с первым столбцом и удаляем те, которые повторяются, и снова упорядочиваем их. для третьего столбца мы проверяем строки с первым и вторым, если похожи, то удаляем, а затем расставляем их. Таким образом, вывод должен выглядеть так, как показано ниже.

Q9ULV4  Q9UNZ5  Q9Y2W1
Q6QEF8  Q9H2K0  Q9UKD2
Q9H6F5          Q9NYF8
Q9GZZ1          
Q9BWS9          

Это не похоже ни на один вопрос, который я задавал; поэтому, пожалуйста, если это все еще не ясно, просто прокомментируйте, я попытаюсь объяснить это


r
person nik    schedule 27.06.2016    source источник
comment
@akrun извините, я не был в сети, да, это ошибка, которую я сделал (опечатка), я исправил свой вопрос   -  person nik    schedule 27.06.2016
comment
@akrun ты прав! однако у меня есть только один голос, и мне понравился его ответ, потому что он или она потратили время на этот ответ, поэтому я просто хотел оценить его / ее время! в противном случае я принимаю более эффективный вариант с меньшим использованием пакета и быстрым ответом, который, вероятно, имеет 4 голоса :-)   -  person nik    schedule 27.06.2016
comment
@docendodiscimus Я выбрал его с добрыми намерениями, чтобы убедиться, что ОП обновит свой пост.   -  person akrun    schedule 27.06.2016


Ответы (4)


Первая строка преобразует df в список L. Вторая строка создает фрейм данных длинной формы long, содержащий значения в столбце 1 и имена столбцов df в столбце 2 в качестве коэффициента. Необходимо сделать это фактором, поскольку уровни сохраняют все имена столбцов, включая те, которые впоследствии удаляются из-за того, что содержат только дубликаты. Кроме того, он сохраняет порядок имен столбцов. Последняя строка удаляет дубликаты, создавая long0. Пакеты не используются.

L <- lapply(df,  function(x) unlist(strsplit(as.character(x), ";")))
long <- transform(stack(L), ind = factor(as.character(ind), levels = names(df)))
long0 <- subset(long, !duplicated(values))

Теперь рассмотрим три возможных формы выхода:

1) полный фрейм данных

> long0
   values ind
1  Q9ULV4  V1
2  Q6QEF8  V1
3  Q9H6F5  V1
4  Q9GZZ1  V1
5  Q9BWS9  V1
6  Q9UNZ5  V2
8  Q9H2K0  V2
11 Q9Y2W1  V3
15 Q9UKD2  V3
17 Q9NYF8  V3

2) список

L0 <- unstack(long0)

давая:

> L0
$V1
[1] "Q9ULV4" "Q6QEF8" "Q9H6F5" "Q9GZZ1" "Q9BWS9"

$V2
[1] "Q9UNZ5" "Q9H2K0"

$V3
[1] "Q9Y2W1" "Q9UKD2" "Q9NYF8"

3) символьная матрица Создайте версию L0, которая заменяет каждый компонент нулевой длины на NA, а затем расширяет длину каждого компонента до максимальной длины, преобразуя ее в матрицу одновременно с помощью sapply.

lens <- lengths(L0)
m0 <- sapply(replace(L0, !lens, NA), "length<-", max(lens))

давая:

> m0
     V1       V2       V3      
[1,] "Q9ULV4" "Q9UNZ5" "Q9Y2W1"
[2,] "Q6QEF8" "Q9H2K0" "Q9UKD2"
[3,] "Q9H6F5" NA       "Q9NYF8"
[4,] "Q9GZZ1" NA       NA      
[5,] "Q9BWS9" NA       NA     

Обновление: некоторые исправления и пояснения.

Примечание 1. Входные данные df в воспроизводимой форме:

df <-
structure(list(V1 = c("", "Q9ULV4;Q6QEF8", "", "", "", "", "Q9H6F5", 
"Q9GZZ1", "Q9BWS9"), V2 = c("Q9UNZ5", "", "", "Q9H6F5", "Q9H2K0", 
"Q9GZZ1", "Q9GZZ1", "", ""), V3 = c("Q9Y2W1", "", "Q9UNZ5", "", 
"Q9ULV4;Q6QEF8", "Q9UKD2", "Q9GZZ1", "Q9NYF8", "")), .Names = c("V1", 
"V2", "V3"), row.names = c(NA, -9L), class = "data.frame")

Примечание 2. В самой последней разрабатываемой версии R "R в разработке (нестабильная) (2016-07-05 r70861)" строка long <- вверху может быть упрощена до long <- stack(L), поскольку stack создает фактор со всеми уровнями в этой версии R.

person G. Grothendieck    schedule 27.06.2016
comment
можно ли удалить вокруг каждой строки? Мне уже понравился твой ответ, спасибо - person nik; 27.06.2016
comment
В самих строках нет кавычек. Кавычки — это то, как R представляет вывод на консоли. Если это все еще важно для вас, попробуйте noquote(L0) и noquote(m0). - person G. Grothendieck; 27.06.2016
comment
когда я делаю это на своих реальных данных, я получаю сообщение об ошибке m0 ‹- do.call(cbind, lapply(L0, as.ts))[TRUE,] Ошибка в ts(x): объект 'ts' должен иметь один или несколько наблюдения, а также считаете ли вы правильным сделать так, чтобы вместо пробела было NA m0[is.na(m0)] ‹- - person nik; 27.06.2016
comment
спасибо теперь работает L0 ‹- lapply(L0, function(x) if (length(x)) x else ), еще раз спасибо и я принял ваш ответ СПАСИБО - person nik; 27.06.2016
comment
это здорово спасибо! Я проверю это сейчас, один вопрос, если я не хочу удалять дубликаты, а упорядочивать их, я просто удаляю !duplicated ? - person nik; 27.06.2016
comment
Да, используйте long и L вместо long0 и L0, если удаление дубликатов не требуется. Внесены некоторые дополнительные улучшения. - person G. Grothendieck; 27.06.2016
comment
спасибо большое бро, не знаю как тебя отблагодарить, ты столько времени на это потратил, спасибо. Я разместил вопрос здесь stackoverflow.com/questions/38062420/ если у вас есть какие-либо идеи, пожалуйста, не стесняйтесь, дайте мне знать - person nik; 27.06.2016

Я бы подошел к этому в два этапа:

1) получить уникальные элементы для каждого столбца и преобразовать в список:

l <- lapply(df, function(x) unique(unlist(strsplit(as.character(x), ";"))))

2) удалить дубликаты, которые появляются в любых предыдущих столбцах

for(i in seq_along(l)) {
  l[[i]] <- setdiff(l[[i]], unlist(l[seq_len(i-1L)]))
}

Причина, по которой я использую list вместо data.frame, заключается в том, что data.frame требует, чтобы все столбцы имели одинаковое количество строк, что здесь не так (если вы не заполните их NA или пустыми строками). В таких случаях лучше всего использовать структуру list.

person talat    schedule 27.06.2016
comment
дискус, спасибо, мне понравился ваш ответ, однако я предпочитаю не использовать цикл, если есть альтернатива, как показано ниже - person nik; 27.06.2016

Я бы сделал это в простом R на основе функции duplicate следующим образом:

lst <- lapply(df, function(x) unlist(strsplit(as.character(x), ";", fixed = TRUE)))
cols <- colnames(df)
seen_entries <- NULL

for (i in (1:ncol(df))) { 
  n_seen_before <- length(seen_entries)
  seen_entries <- c(seen_entries, lst[[cols[i]]])
  lst[[cols[i]]] <- lst[[cols[i]]][(!duplicated(seen_entries))[
                                        (n_seen_before+1):length(seen_entries)]]
}

Выход:

> lst
$V1
[1] "Q9ULV4" "Q6QEF8" "Q9H6F5" "Q9GZZ1" "Q9BWS9"

$V2
[1] "Q9UNZ5" "Q9H2K0"

$V3
[1] "Q9Y2W1" "Q9UKD2" "Q9NYF8"

Вероятно, есть более элегантное решение, использующее, например. data.table или что-то подобное.

person Patrick Roocks    schedule 27.06.2016
comment
спасибо, патрик, мне понравился твой ответ, но он использует цикл - person nik; 27.06.2016

Мы можем попробовать

lst <- lapply(df, function(x) unique(unlist(strsplit(as.character(x), ";"))))
lapply(seq_along(lst), function(i) {
            v1 <- unlist(lst[seq(i)])
            setdiff(lst[[i]], v1[duplicated(v1)])})
#[[1]]
#[1] "Q9ULV4" "Q6QEF8" "Q9H6F5" "Q9GZZ1" "Q9BWS9"

#[[2]]
#[1] "Q9UNZ5" "Q9H2K0"

#[[3]]
#[1] "Q9Y2W1" "Q9UKD2" "Q9NYF8"
person akrun    schedule 27.06.2016