#python #pandas #pandas-groupby
Вопрос:
У меня есть фрейм данных с ID
date
и number
столбцами , и я хотел бы создать новый столбец, который принимает среднее значение всех чисел для этого конкретного ID
, НО включает только числа в среднем, где дата меньше даты этой строки. Как бы я это сделал?
df = (pd.DataFrame({'ID':['1','1','1','1','2','2'],'number':['1','4','1','4','2','5'], 'date':['2021-10-19','2021-10-16','2021-10-16','2021-10-15','2021-10-19','2021-10-10']}) .assign(date = lambda x: pd.to_datetime(x.date)) .assign(mean_no_from_previous_dts = lambda x: x[x.datelt;??].groupby('ID').number.transform('mean')) )
это то, что я хотел бы получить в качестве вывода
ID number date mean_no_from_previous_dts 0 1 1 2021-10-19 3.0 = mean(4 1 4) 1 1 4 2021-10-16 2.5 = mean(4 1) 2 1 1 2021-10-16 4.0 = mean(1) 3 1 4 2021-10-15 0.0 = 0 (as it's the first entry for this date and ID - this number doesnt matter, can e something else) 4 2 2 2021-10-19 5.0 = mean(5) 5 2 5 2021-10-10 0.0 = 0 (as it's the first entry for this date and ID)
так, например, первая запись столбца mean_no_from_previous_dts
-это среднее значение (4 1 4)
: первое 4
происходит из столбца number
и 2-й строки, потому что 2021-10-16 (дата во 2-й строке) меньше, чем 2021-10-19 (дата в 1-й строке). Это 1
происходит из 3-го ряда, потому что 2021-10-16 меньше, чем 2021-10-19. Второй 4
идет из 4-го ряда, потому что 2021-10-15 меньше, чем 2021-10-19. Это для ID = 1
того же самого, для ID = 2
Комментарии:
1.
where date is smaller than the current date.
таким образом, это означает, что все ценности включены, потому что сегодня есть2021-10-20
?2. нет, я имею в виду дату текущей строки. Итак, для первой строки: 2021-10-16, 2021-10-16 и 2021-10-15 меньше, чем 2021-10-19, поэтому возьмите среднее значение: (4 1 4)/3
3. Эй, я не понимаю — что такое столбец no_of_previous_dts?
4. Я попытался отредактировать его и сделать более понятным.
Ответ №1:
Вот решение с широковещательной передачей numpy для групп:
df = (pd.DataFrame({'ID':['1','1','1','1','2','2'],'number':['1','4','1','4','2','5'], 'date':['2021-10-19','2021-10-16','2021-10-16','2021-10-15','2021-10-19','2021-10-10']}) .assign(date = lambda x: pd.to_datetime(x.date), number = lambda x: x['number'].astype(int)) )
def f(x): arr = x['date'].to_numpy() m = arr lt;= arr[:, None] #remove rows with same values - set mask to False np.fill_diagonal(m, False) #set greater values to `NaN` and get mean without NaNs m = np.nanmean(np.where(m, x['number'].to_numpy(), np.nan).astype(float), axis=1) #assign to new column x['no_of_previous_dts'] = m return x #last value is set to 0 per groups df = df.groupby('ID').apply(f).fillna({'no_of_previous_dts':0}) print (df) ID number date no_of_previous_dts 0 1 1 2021-10-19 3.0 1 1 4 2021-10-16 2.5 2 1 1 2021-10-16 4.0 3 1 4 2021-10-15 0.0 4 2 2 2021-10-19 5.0 5 2 5 2021-10-10 0.0
Комментарии:
1. большое спасибо. Это очень медленно с большим кадром данных. Неужели для этого нет метода панд? Может быть, что-то с роллингом или рангом?
2. @corianne1234 — Если использовать
df['g'] = df.groupby(['ID','date']).cumcount()
, иdf1 = df.pivot('ID', ['date', 'g'], 'number').sort_index(axis=1)
что тогдаprint (df1.shape)
?