2015-07-03 4 views
2

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

В частности - если есть 2 дубликатов записей в столбцах 1, Я хотел бы строку удалена с более низким значением в колонке 2

Или, если есть больше чем 2 одинаковые записи в столбцах 1, то я хотел бы, строка с медианным значением в строке 2 для сохранения.

Таким образом, для кадра данных

a <- c(rep("A", 3), rep("B", 3), rep("C",1), rep("D",1), rep("D",1)) 
b <- c(1,2,3,4,5,6,4,7,6) 
df <-data.frame(a,b) 

станет

a <- c(rep("A", 1), rep("B", 1), rep("C",1), rep("D",1)) 
b <- c(2,5,4,7) 
df <-data.frame(a,b) 

Я Пытался функции, специфический() и дублируется(), но не может найти аргументы, которые соответствуют этим критериям. Любая помощь очень ценится.

+0

Для базы R вы также можете просмотреть '? Aggregate'. – SimonG

ответ

3

Использование dplyr:

library(dplyr) 

df %>% group_by(a) %>% 
    summarise(b = ifelse(n() == 2, min(b), median(b))) 

    a b 
1 A 2 
2 B 5 
3 C 4 
4 D 6 

В вашем вопросе, вы сказали, что вы хотите "нижний" значение, в случае, если есть две строки, которые будут давать D = 6, а не D = 7. Если вы имели в виду первую строку, которая появляется в кадре данных, вы можете сделать это:

df %>% group_by(a) %>% 
    summarise(b = ifelse(n() == 2, b[1], median(b))) 
+0

Отлично - большое спасибо. Все отлично работали! – MLyall

4

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

library(data.table) 
setDT(df)[, list(b=if(.N==2) min(b) else median(b)) , by = a] 
# a b 
#1: A 2 
#2: B 5 
#3: C 4 
#4: D 6 

Или подобный вариант с aggregate

aggregate(b~a, df, FUN=function(x) if(length(x)==2) min(x) else median(x)) 
# a b 
#1 A 2 
#2 B 5 
#3 C 4 
#4 D 6 

Или

library(sqldf) 
sqldf('select a, 
     case 
      when count(b) is 2 then min(b) 
      else median(b) 
     end b 
     from df 
     group by a') 
# a b 
#1 A 2 
#2 B 5 
#3 C 4 
#4 D 6 

на основе ожидаемого выхода показал, последняя строка D 7, так что если мы выбираем первое наблюдение, когда длина группы равна 2,

setDT(df)[, list(b=if(.N==2) b[1L] else median(b)) , by = a] 
# a b 
#1: A 2 
#2: B 5 
#3: C 4 
#4: D 7 

Или

aggregate(b~a, df, FUN=function(x) if(length(x)==2) x[1L] else median(x)) 
# a b 
#1 A 2 
#2 B 5 
#3 C 4 
#4 D 7 

Или

sqldf('select a, 
      case 
      when count(b) is 2 and min(rowid) then b 
      else median(b) 
      end b 
     from df 
     group by a') 
# a b 
#1 A 2 
#2 B 5 
#3 C 4 
#4 D 7 

EDIT изменил первое наблюдение в min после того как я увидел @ eipi10 посте. Не прочитал сообщение OP правильно, и ожидаемый вывод OP не соответствует описанию.

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