2013-11-19 1 views
0

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

Year | ID | Month | Use | 
---------------------------- 
2009 101 1 103 

2009 101 2 209 

2009 101 3 375 

2009 101 4 360 

2010 101 1 170 

2010 101 2 381 

2010 101 3 275 

2010 101 4 260 

2009 102 1 263 

2009 102 2 234 

2009 102 3 45 

2009 102 4 275 

2010 102 1 469 

2010 102 2 107 

2010 102 3 354 

2010 102 4 436 

В идеале я хотел бы вернуть три матрицы, max1, max2, max3 с колоннами ID, Year, Max (или второй максимум или третий максимум, соответственно) Так max1 = [101, 2009, 375, 101, 2010, 381, 102, 2009, 275, 102, 2010, 469] и т.д.

Мой первоначальный подход должен был сделать вложенным цикл с listofIDs и listofYears как доменами ID и Year, как:

for i in 1:length(listofIDs){ 

for y in 1:length(listofYears){ 

monthlylist<-sqldf("select Month, Use from Dataframe where ID=listofIDs[i] and Year=listofYears[y]") 

, а затем сортировать monthlylist и вытащить Макса и т.д. Но sqldf не будут читать такие переменные, как, что, так что я бы однозначно определить, где ID = 101, где ID = 102 каждый раз.

Любые идеи о том, как получить sqldf, чтобы распознать мои переменные, или лучший способ найти максимальный, второй максимальный и третий максимальный агрегированный по году и идентификатору? Я работаю с большими наборами данных, так что идеально, что не займет навсегда.

ответ

2

Следующий код создает список из трех фреймов данных (dat ваш исходный кадр данных):

lapply(seq(3), function(x) 
    aggregate(Use ~ Year + ID, dat, function(y) 
    y[order(-y)][x])) 

Результат:

[[1]] 
    Year ID Use 
1 2009 101 375 
2 2010 101 381 
3 2009 102 275 
4 2010 102 469 

[[2]] 
    Year ID Use 
1 2009 101 360 
2 2010 101 275 
3 2009 102 263 
4 2010 102 436 

[[3]] 
    Year ID Use 
1 2009 101 209 
2 2010 101 260 
3 2009 102 234 
4 2010 102 354 

Как это работает:

Функция lapply используется для применения другой функции несколько раз. Команда seq(3) генерирует вектор чисел от 1 до 3. Параметр x представляет одно из этих чисел. Функция aggregate используется для применения другой функции к значениям Use, сгруппированных по Year и ID. Параметр y представляет значения Use в одной группе. Команда y[order(-y)] сортирует значения Use в порядке убывания. Впоследствии [x] используется для извлечения первого, второго и третьего элементов, соответственно, этого упорядоченного вектора.

+0

Спасибо! Это дает правильный ответ. Если у вас есть время, вы можете объяснить, как это работает? Я довольно новичок в R и пытался посмотреть документацию на функции, которые вы используете, но я все еще немного потерял. Кроме того, чтобы получить min, second min и third min, вы бы изменили y [порядок (-y)] [x] на y [порядок (y)] [x]? (Просто догадаться) –

+0

@ user2930124 Вы правы. Команда 'order' упорядочивает значения в порядке возрастания. Из-за '-' значения располагаются в порядке убывания. –

+0

@ user2930124 Я добавил объяснение. –

1

Сначала настроить тестовые данные в легко воспроизводимой форме:

# set up test data 

Lines <- "Year ID Month Use 
2009 101 1 103 
2009 101 2 209 
2009 101 3 375 
2009 101 4 360 
2010 101 1 170 
2010 101 2 381 
2010 101 3 275 
2010 101 4 260 
2009 102 1 263 
2009 102 2 234 
2009 102 3 45 
2009 102 4 275 
2010 102 1 469 
2010 102 2 107 
2010 102 3 354 
2010 102 4 436 
" 
DF <- read.table(text = Lines, header = TRUE) 

Теперь у нас есть входные данные здесь некоторые подходы:

1) sqldf/SQLite Следующие три SQL заявления должны рассчитать эти величины. Если они работают слишком медленно, вы можете попробовать добавить индекс Year, ID.Обратите внимание, что три SQL оператора одинаковы для from статей за исключением:

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

library(sqldf) 

max1 <- sqldf("select Year, ID, max(Use) Use 
    from DF 
    group by Year, ID") 

max2 <- sqldf("select Year, ID, max(Use) Use 
    from (select Year, ID, Use from DF 
     except select * from max1) 
    group by Year, ID") 

max3 <- sqldf("select Year, ID, max(Use) Use 
    from (select Year, ID, Use from DF 
     except select * from max1 
     except select * from max2) 
    group by Year, ID") 

2) sqldf/PostgreSQL выше для sqldf с SQLite, но это еще проще с sqldf и PostgreSQL, потому что тогда мы могли бы использовать функцию окна PostgreSQL rank(). (Существует больше информации об использовании PostgreSQL с sqldf here.)

library(RPostgreSQL) 
library(sqldf) 

DF2 <- sqldf('select *, rank() over (partition by "Year", "ID" order by "Use" desc) 
       from "DF"') 
split(DF2[1:4], DF2$rank)[1:3] 

Последняя строка может быть альтернативно заменен следующим образом:

lapply(1:3, function(r) subset(DF2, rank == r)[1:4]) 

Если мы хотим чистый SQL решение затем:

max1 <- sqldf('select "Year", "ID", "Month", "Use" from "DF2" where "rank" = 1') 
max2 <- sqldf('select "Year", "ID", "Month", "Use" from "DF2" where "rank" = 2') 
max3 <- sqldf('select "Year", "ID", "Month", "Use" from "DF2" where "rank" = 3') 

или для получения списка фреймов данных:

lapply(1:3, function(r) 
    fn$sqldf('select "Year", "ID", "Month", "Use" from "DF2" where "rank" = $r')) 

3) ave Его не так сложно сделать это прямолинейно. Здесь ранг 1 - самый большой, второй по величине ранг 2 и т. Д., Поэтому мы просто разделились на Rank, как и в предыдущем решении, и сделаем первый три компонента:

Rank <- with(DF, ave(-Use, Year, ID, FUN = rank)) 
split(DF, Rank)[1:3] 

Это также будет работать на месте последней строки:

lapply(1:3, function(r) subset(DF, Rank == r)) 

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

ОБНОВЛЕНИЕ: Написал второе решение.

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

  • Нет связанных вопросов^_^