У меня есть набор данных ниже, и я хотел бы найти максимум по подмножеству
Набор данных

StudentID Indicator Value  
100 N 30  
100 N 35  
100 N 28  
100 Y 20  
100 N 29  
100 N 60  
200 N 40  
200 N 35  
200 Y 20  
200 N 24  
200 N 35  

Я хотел бы, чтобы результат был таким, как показано ниже:
< Сильный > Результат

StudentID Indicator Value Max  
100 N 30 35  
100 N 35 35  
100 N 28 35  
100 N 29 60   
100 N 60 60  
200 N 40 40  
200 N 35 40  
200 N 24 35  
200 N 35 35  

Поэтому, по сути, всякий раз, когда индикатор изменяется с N на Y, мне нужно рассматривать строки по studentID и IndicatorID как один блок, вычислять максимальное значение этого блока и переходить к следующей итерации.

-3
Vinay 27 Фев 2018 в 05:10

4 ответа

Лучший ответ

Решение, использующее в R.

library(dplyr)

dat2 <- dat %>%
  group_by(StudentID) %>%
  mutate(Group = cumsum(Indicator %in% "Y")) %>%
  filter(!Indicator %in% "Y") %>%
  group_by(StudentID, Group) %>%
  mutate(Max = max(Value)) %>%
  ungroup() %>%
  select(-Group) %>%
  as.data.frame(stringsAsFactors = FALSE)
dat2
#   StudentID Indicator Value Max
# 1       100         N    30  35
# 2       100         N    35  35
# 3       100         N    28  35
# 4       100         N    29  60
# 5       100         N    60  60
# 6       200         N    40  40
# 7       200         N    35  40
# 8       200         N    24  35
# 9       200         N    35  35

< Сильный > DATA

dat <- read.table(text = "StudentID Indicator Value  
100 N 30  
                  100 N 35  
                  100 N 28  
                  100 Y 20  
                  100 N 29  
                  100 N 60  
                  200 N 40  
                  200 N 35  
                  200 Y 20  
                  200 N 24  
                  200 N 35  ",
                  header = TRUE, stringsAsFactors = FALSE)
1
www 27 Фев 2018 в 02:22

Вот вариант использования pandas из python. Мы создаем группирующую переменную, получая кумулятивную сумму логического вывода (dat.Indicator == "Y", затем подставляем в строку строки, удаляя строки, у которых «Indicator» как «Y», сгруппированные по «StudentID», «Group», получаем max для 'Value' с transform, присвойте его для 'Value' и drop столбцы, которые не нужны

dat['Group'] = (dat.Indicator == "Y").cumsum()

datS = dat[dat.Indicator != "Y"]
datS1 = datS.copy()
datS1['Value'] = datS.groupby(['StudentID', 'Group'])['Value'].transform('max')
datS1.drop('Group', axis = 1, inplace = True)
datS1

-вывод

enter image description here


Опция base R будет ave

dat$Value <- with(dat, ave(Value, cumsum(Indicator == "Y"), FUN = max))
subset(dat, Indicator != "Y")
#    StudentID Indicator Value
#1        100         N    35
#2        100         N    35
#3        100         N    35
#5        100         N    60
#6        100         N    60
#7        200         N    60
#8        200         N    60
#10       200         N    35
#11       200         N    35

Данные

import pandas as pd
dat = pd.DataFrame({'StudentID': [100, 100, 100, 100, 100, 100, 200, 200, 200, 200, 200],
               'Indicator':[ "N", "N", "N", "Y", "N", "N", "N", "N", "Y", "N", "N"],
               'Value':[30, 35, 28, 20, 29, 60, 40, 35, 20, 24, 35]})

#R
dat <-structure(list(StudentID = c(100L, 100L, 100L, 100L, 100L, 100L, 
 200L, 200L, 200L, 200L, 200L), Indicator = c("N", "N", "N", "Y", 
"N", "N", "N", "N", "Y", "N", "N"), Value = c(35L, 35L, 35L, 
60L, 60L, 60L, 60L, 60L, 35L, 35L, 35L)), .Names = c("StudentID", 
 "Indicator", "Value"), row.names = c(NA, -11L), class = "data.frame")
1
akrun 27 Фев 2018 в 05:15

Вам не хватает переменной для обозначения групп. Это легко сделать в SAS, используя параметр notsorted в выражении by.

data grouped ;
  retain group 0;
  set have ;
  by studentid indicator notsorted;
  group + first.indicator;
run;

Существует несколько способов генерирования среднего значения по группам теперь, когда они определены. PROC SQL облегчает это, автоматически возвращая агрегатные значения обратно в подробные строки.

proc sql ;
 select *,max(value) as max
   from grouped
   group by group
 ;
quit;

Результаты:

group  StudentID  Indicator     Value       max

   1        100  N                35        35
   1        100  N                30        35
   1        100  N                28        35
   2        100  Y                20        20
   3        100  N                60        60
   3        100  N                29        60
   4        200  N                40        40
   4        200  N                35        40
   5        200  Y                20        20
   6        200  N                35        35
   6        200  N                24        35

Я не уверен, почему ваш пример вывода удалил группы, у которых INDICATOR = 'Y', но вы можете просто добавить предложение where, чтобы удалить их.

0
Tom 27 Фев 2018 в 03:54

Решение с использованием ddply из пакета plyr.

Предполагая, что это хранится как фрейм данных с именем df

output_df <- plyr::ddply(df, c("StudentID", "Indicator"), numcolwise(max))

ddply применяет функцию к подмножеству данных. Первый аргумент - это данные, к которым мы хотим применить его, второй - имена столбцов, по которым мы хотим сгруппировать его. Финал - это функция, которую мы хотим применить. Поскольку мы применяем его к столбцу подмножества, нам нужно обернуть max в numcolwise.

Вывод может иметь смешное имя для последнего столбца, но вы можете установить его с помощью names(output_df)[3] <- "Max".

Теперь нам просто нужно объединить это с оригинальным кадром.

df$Max <- rep(output_df$Max, times = table(df$StudentID))

times аргумент rep говорит, сколько раз повторять каждый элемент первого аргумента. Использование функции table позволяет определить, сколько раз встречается каждый идентификатор студента. Это будет работать только в том случае, если идентификаторы студентов в порядке. Если это не так, тогда потребуется другой подход.

Всего 3 строки кода

output_df <- plyr::ddply(df, c("StudentID", "Indicator"), numcolwise(max))
names(output_df)[3] <- "Max"
df$Max <- rep(output_df$Max, times = table(df$StudentID))
-1
LachlanO 27 Фев 2018 в 02:35