#python #pandas #dataframe #function #date
Вопрос:
У меня есть фрейм данных в виде:
big fc15 fc16 fc17 fc18 fc19 ... fc23 fc24 fc25 fc26 fc27 fc28
28 2018-10-01 2019-02-01 2019-06-04 2019-08-06 2019-10-07 ... 2015-01-01 2015-01-01 2015-01-01 2015-01-01 2015-01-01 2015-01-01
27 2015-01-01 2019-02-01 2015-01-01 2015-01-01 2015-01-01 ... 2015-01-01 2015-01-01 2015-01-01 2015-01-01 2015-01-01 2015-01-01
20 2018-10-01 2019-02-01 2019-06-04 2019-08-06 2019-10-07 ... 2015-01-01 2015-01-01 2015-01-01 2015-01-01 2015-01-01 2015-01-01
21 NaT NaT NaT NaT NaT ... NaT NaT NaT NaT NaT NaT
24 2018-10-01 2019-02-01 2019-06-04 2019-08-06 2019-10-07 ... 2015-01-01 2020-09-03 2015-01-01 2015-01-01 2021-03-03 2021-05-05
25 2018-10-01 2019-02-01 2019-06-04 2019-08-06 2019-10-07 ... 2015-01-01 2020-09-03 2015-01-01 2021-01-06 2021-03-03 2015-01-01
26 2018-10-01 2019-02-01 2019-06-04 2019-08-06 2019-10-07 ... 2015-01-01 2015-01-01 2020-11-05 2021-01-06 2015-01-01 2015-01-01
23 2015-01-01 2015-01-01 2015-01-01 2019-08-06 2019-10-07 ... 2020-07-13 2020-09-03 2020-11-05 2021-01-06 2021-03-03 2015-01-01
22 NaT NaT NaT NaT NaT ... NaT NaT 2020-11-05 2021-01-06 2021-03-03 2021-05-05
27 2018-10-01 2019-02-01 2019-06-04 2015-01-01 2019-10-07 ... 2015-01-01 2015-01-01 2015-01-01 2015-01-01 2015-01-01 2015-01-01
Итак, в зависимости от big
столбца он должен рассчитать разницу (timedelta) между датой в столбце с одинаковым размером, например, if big == 24 then fc24 - max(fc23, fc22, fc21, fc20, fc19, fc18)
и так далее … НО если big > max(big)
или максимальное количество столбцов, которое в данном случае равно 28 (из-за fc28
столбца (последнего столбца)), предположим, что 29, оно должно вычислить today_date - max(fc28, fc27, fc26, fc25, fc24)
.
Я попробовал свою функцию в качестве:
def estimated_time(df):
today_date = datetime.datoday()
df['time_without_offer'] = np.where(df['big'] == 16, (df['fc16'] - df['fc15']).astype('timedelta64[D]'),
np.where(df['big'] == 17, (df['fc17'] - df[['fc15', 'fc16']].max(axis = 1)).astype('timedelta64[D]'),
np.where(df['big'] == 18, (df['fc18'] - df[['fc15', 'fc16', 'fc17']].max(axis = 1)).astype('timedelta64[D]'),
np.where(df['big'] == 19, (df['fc19'] - df[['fc15', 'fc16', 'fc17', 'fc18']].max(axis = 1)).astype('timedelta64[D]'),
np.where(df['big'] == 20, (df['fc20'] - df[['fc15', 'fc16', 'fc17', 'fc18', 'fc19']].max(axis = 1)).astype('timedelta64[D]'),
np.where(df['big'] == 21, (df['fc21'] - df[['fc15', 'fc16', 'fc17', 'fc18', 'fc19', 'fc20']].max(axis = 1)).astype('timedelta64[D]'),
np.where(df['big'] == 22, (df['fc22'] - df[['fc16', 'fc17', 'fc18', 'fc19', 'fc20', 'fc21']].max(axis = 1)).astype('timedelta64[D]'),
np.where(df['big'] == 23, (df['fc23'] - df[['fc17', 'fc18', 'fc19', 'fc20', 'fc21', 'fc22']].max(axis = 1)).astype('timedelta64[D]'),
np.where(df['big'] == 24, (df['fc24'] - df[['fc18', 'fc19', 'fc20', 'fc21', 'fc22', 'fc23']].max(axis = 1)).astype('timedelta64[D]'),
np.where(df['big'] == 25, (df['fc25'] - df[['fc19', 'fc20', 'fc21', 'fc22', 'fc23', 'fc24']].max(axis = 1)).astype('timedelta64[D]'),
np.where(df['big'] == 26, (df['fc26'] - df[['fc20', 'fc21', 'fc22', 'fc23', 'fc24', 'fc25']].max(axis = 1)).astype('timedelta64[D]'),
np.where(df['big'] == 27, (df['fc27'] - df[['fc21', 'fc22', 'fc23', 'fc24', 'fc25', 'fc26']].max(axis = 1)).astype('timedelta64[D]'),
np.where(df['big'] == np.max(df['big']) 1, (pd.to_datetime(today_date) - df[['fc22', 'fc23', 'fc24', 'fc25', 'fc26', 'fc27', 'fc28']].max(axis = 1)).astype('timedelta64[D]'), ...))))))
и моя функция, кажется, работает правильно, но проблема в том, что я не хочу обновлять функцию при добавлении нового столбца fcXX
.
Знаете ли вы способ, как уменьшить эту функцию? Это должно быть очень полезно.
Ответ №1:
Это черновик решения, потому что я не совсем уверен в паре вопросов:
сколько столбцов вы хотите включить в расчет максимумов[изменяемая сумма с минимальным номером столбца],
каковы максимальные и минимальные значения df.big
,
как обрабатывать max(big) [если до назначения minuent].
Но в целом он масштабируется до произвольного количества столбцов.
О groupby.apply
программе : она выполняется только для каждой группы (строк с одинаковым номером big
), а не для каждой строки.
Установка:
import pandas as pd
import numpy as np
from datetime import datetime as dt
np.random.seed(1234)
def pp_rounded(start, end, n):
start_u = start.value//10**9
end_u = end.value//10**9
output = pd.Series(
pd.DatetimeIndex(
(10**9*np.random.randint(start_u, end_u, n, dtype=np.int64)
).view('M8[ns]')
)
).dt.floor("1D")
return output
start = pd.to_datetime('2010-01-01')
end = pd.to_datetime('2020-01-01')
rows_num = 100_000
biglist = np.random.randint(16, 30, rows_num)
df = pd.DataFrame(biglist, columns=["big"])
for i in range(15, 29):
df[f"fc{i}"] = pp_rounded(start, end, rows_num)
big_max = df.big.max()
col_min = 15
Основные функции:
def pick_col_names(big_grp):
global col_min, big_max
number_columns_to_include = 6
start = min(big_max, big_grp) - 1
end = max(col_min, start - number_columns_to_include) - 1
column_names = [f'fc{j}' for j in range(start, end, -1)]
return column_names
def calc_time_without_offer(grp, big_max):
big = grp.big.iloc[0]
column_names = pick_col_names(big)
minuend = None
if big >= big_max:
minuend = pd.to_datetime(dt.today().date())
else:
minuend = grp[f"fc{big}"]
grp['time_without_offer'] = minuend - grp[column_names].max(axis=1)
return grp
Использование:
df = df.groupby("big").apply(calc_time_without_offer, big_max)
df["time_without_offer"]
Выходы:
0 -1175 days
1 -634 days
2 -1233 days
3 108 days
4 -1546 days
...
99995 -1603 days
99996 -457 days
99997 1965 days
99998 882 days
99999 -2390 days
Name: time_without_offer, Length: 100000, dtype: timedelta64[ns]