Create the evolution of exposure from inception and maturity of a list of loans in Python/Pandas
Question:
I have a DataFrame with a list of loans, with inception date, maturity, amount.
I would like to create a DataFrame with the evolution of the exposure as follows:
from:
contract
amount
inception
maturity
1
100
31/12/2022
31/12/2042
2
90
31/12/2023
31/12/2052
3
50
31/12/2024
31/12/2035
to:
date
1
2
3
31/12/2022
100
0
0
31/12/2023
100
90
0
31/12/2024
100
90
50
31/12/2025
100
90
50
…
100
90
50
31/12/2042
0
90
0
…
0
90
0
31/12/2052
0
0
0
Thanks!
Answers:
First convert to datetimes by to_datetime
, then subtract years and repeat rows by DataFrame.loc
with Index.repeat
, create counter column by GroupBy.cumcount
and add to years, last pivoting by DataFrame.pivot_table
with aggfunc='sum'
for aggregate sum if duplicated values:
df['inception'] = pd.to_datetime(df['inception'])
df['maturity'] = pd.to_datetime(df['maturity'])
df = (df.loc[df.index.repeat(df['maturity'].dt.year.sub(df['inception'].dt.year) + 1)]
.assign(y = lambda x: x.groupby(level=0).cumcount().add(x['inception'].dt.year))
.pivot_table(index='y',
columns='contract',
values='amount',
fill_value=0,
aggfunc='sum')
.rename(lambda x: f'31/12/{x}'))
print (df)
contract 1 2 3
y
31/12/2022 100 0 0
31/12/2023 100 90 0
31/12/2024 100 90 50
31/12/2025 100 90 50
31/12/2026 100 90 50
31/12/2027 100 90 50
31/12/2028 100 90 50
31/12/2029 100 90 50
31/12/2030 100 90 50
31/12/2031 100 90 50
31/12/2032 100 90 50
31/12/2033 100 90 50
31/12/2034 100 90 50
31/12/2035 100 90 50
31/12/2036 100 90 0
31/12/2037 100 90 0
31/12/2038 100 90 0
31/12/2039 100 90 0
31/12/2040 100 90 0
31/12/2041 100 90 0
31/12/2042 100 90 0
31/12/2043 0 90 0
31/12/2044 0 90 0
31/12/2045 0 90 0
31/12/2046 0 90 0
31/12/2047 0 90 0
31/12/2048 0 90 0
31/12/2049 0 90 0
31/12/2050 0 90 0
31/12/2051 0 90 0
31/12/2052 0 90 0
EDIT: You can subtract each 5 values per amount
if True
s in is_instalment
by subtract column by multiplied counter by 5
:
print (df)
contract amount inception maturity is_instalment
0 1 100 31/12/2022 31/12/2042 True
1 2 90 31/12/2023 31/12/2052 False
2 3 50 31/12/2024 31/12/2035 False
df['inception'] = pd.to_datetime(df['inception'])
df['maturity'] = pd.to_datetime(df['maturity'])
df['y'] = df['inception'].dt.year
df1 = df.loc[df.index.repeat(df['maturity'].dt.year.sub(df['y']) + 1)].copy()
df1['counter'] = df1.groupby(level=0).cumcount()
df1['Date'] = df1['y'].add(df1['counter'])
df1['amount'] = df1['amount'].mask(df1['is_instalment'],
df1['amount'].sub(df1['counter'].mul(5)))
df2 = df1.pivot_table(index='Date',
columns='contract',
values='amount',
fill_value=0,
aggfunc='sum')
print (df2)
contract 1 2 3
Date
2022 100 0 0
2023 95 90 0
2024 90 90 50
2025 85 90 50
2026 80 90 50
2027 75 90 50
2028 70 90 50
2029 65 90 50
2030 60 90 50
2031 55 90 50
2032 50 90 50
2033 45 90 50
2034 40 90 50
2035 35 90 50
2036 30 90 0
2037 25 90 0
2038 20 90 0
2039 15 90 0
2040 10 90 0
2041 5 90 0
2042 0 90 0
2043 0 90 0
2044 0 90 0
2045 0 90 0
2046 0 90 0
2047 0 90 0
2048 0 90 0
2049 0 90 0
2050 0 90 0
2051 0 90 0
2052 0 90 0
I have a DataFrame with a list of loans, with inception date, maturity, amount.
I would like to create a DataFrame with the evolution of the exposure as follows:
from:
contract | amount | inception | maturity |
---|---|---|---|
1 | 100 | 31/12/2022 | 31/12/2042 |
2 | 90 | 31/12/2023 | 31/12/2052 |
3 | 50 | 31/12/2024 | 31/12/2035 |
to:
date | 1 | 2 | 3 |
---|---|---|---|
31/12/2022 | 100 | 0 | 0 |
31/12/2023 | 100 | 90 | 0 |
31/12/2024 | 100 | 90 | 50 |
31/12/2025 | 100 | 90 | 50 |
… | 100 | 90 | 50 |
31/12/2042 | 0 | 90 | 0 |
… | 0 | 90 | 0 |
31/12/2052 | 0 | 0 | 0 |
Thanks!
First convert to datetimes by to_datetime
, then subtract years and repeat rows by DataFrame.loc
with Index.repeat
, create counter column by GroupBy.cumcount
and add to years, last pivoting by DataFrame.pivot_table
with aggfunc='sum'
for aggregate sum if duplicated values:
df['inception'] = pd.to_datetime(df['inception'])
df['maturity'] = pd.to_datetime(df['maturity'])
df = (df.loc[df.index.repeat(df['maturity'].dt.year.sub(df['inception'].dt.year) + 1)]
.assign(y = lambda x: x.groupby(level=0).cumcount().add(x['inception'].dt.year))
.pivot_table(index='y',
columns='contract',
values='amount',
fill_value=0,
aggfunc='sum')
.rename(lambda x: f'31/12/{x}'))
print (df)
contract 1 2 3
y
31/12/2022 100 0 0
31/12/2023 100 90 0
31/12/2024 100 90 50
31/12/2025 100 90 50
31/12/2026 100 90 50
31/12/2027 100 90 50
31/12/2028 100 90 50
31/12/2029 100 90 50
31/12/2030 100 90 50
31/12/2031 100 90 50
31/12/2032 100 90 50
31/12/2033 100 90 50
31/12/2034 100 90 50
31/12/2035 100 90 50
31/12/2036 100 90 0
31/12/2037 100 90 0
31/12/2038 100 90 0
31/12/2039 100 90 0
31/12/2040 100 90 0
31/12/2041 100 90 0
31/12/2042 100 90 0
31/12/2043 0 90 0
31/12/2044 0 90 0
31/12/2045 0 90 0
31/12/2046 0 90 0
31/12/2047 0 90 0
31/12/2048 0 90 0
31/12/2049 0 90 0
31/12/2050 0 90 0
31/12/2051 0 90 0
31/12/2052 0 90 0
EDIT: You can subtract each 5 values per amount
if True
s in is_instalment
by subtract column by multiplied counter by 5
:
print (df)
contract amount inception maturity is_instalment
0 1 100 31/12/2022 31/12/2042 True
1 2 90 31/12/2023 31/12/2052 False
2 3 50 31/12/2024 31/12/2035 False
df['inception'] = pd.to_datetime(df['inception'])
df['maturity'] = pd.to_datetime(df['maturity'])
df['y'] = df['inception'].dt.year
df1 = df.loc[df.index.repeat(df['maturity'].dt.year.sub(df['y']) + 1)].copy()
df1['counter'] = df1.groupby(level=0).cumcount()
df1['Date'] = df1['y'].add(df1['counter'])
df1['amount'] = df1['amount'].mask(df1['is_instalment'],
df1['amount'].sub(df1['counter'].mul(5)))
df2 = df1.pivot_table(index='Date',
columns='contract',
values='amount',
fill_value=0,
aggfunc='sum')
print (df2)
contract 1 2 3
Date
2022 100 0 0
2023 95 90 0
2024 90 90 50
2025 85 90 50
2026 80 90 50
2027 75 90 50
2028 70 90 50
2029 65 90 50
2030 60 90 50
2031 55 90 50
2032 50 90 50
2033 45 90 50
2034 40 90 50
2035 35 90 50
2036 30 90 0
2037 25 90 0
2038 20 90 0
2039 15 90 0
2040 10 90 0
2041 5 90 0
2042 0 90 0
2043 0 90 0
2044 0 90 0
2045 0 90 0
2046 0 90 0
2047 0 90 0
2048 0 90 0
2049 0 90 0
2050 0 90 0
2051 0 90 0
2052 0 90 0