'Perform a specific calculation in a dataframe based on number of days in each month

I have dataframe as shown below. Which consist of customers last 3 months number of transactions.

id     age_days    n_month3     n_month2     n_month1
1      201         60           15           30            
2      800         0            15           5            
3      800         0            0            10           
4      100         0            0            0             
5      600         0            6            5            
6      800         0            0            15           
7      500         10           10           30            
8      200         0            0            0             
9      500         0            0            0

From the above I would like to derive a column called recency as shown in the explanations

Explanation:

month3 is the current month

m3 = number of days of current month m2 = number of days of previous month m1 = number of days of the month of 2 months back from current month

if df["n_month3"] != 0:
    recency = m3 / df["n_month3"]
elif df["n_month2"] != 0:
    recency = m3 + (m2 / df["n_month2"])
elif df["n_month1"] != 0:
    recency = m3 + m2 + (m1 / df["n_month1"])
else:
    if df["age_days"] <= (m3 + m2 + m1):
        recency = df["age_days"]
    else:
        recency = (m3 + m2 + m1) + 1

Expected output:

Let say current month is April, then

m3 = 30 m2 = 31 m1 = 28

id     age_days    n_month3     n_month2     n_month1      recency
1      201         60           15           30            (m3/60) = 30/60 = 0.5
2      800         0            15           5             m3 + (m2/15) = 30 + 31/15 = 32   
3      800         0            0            10            m3 + m2 + m1/10 = 30 + 31 + 28/10         
4      100         0            0            0             m3+m2+m1+1 = 90    
5      600         0            6            5             m3 + (m2/6) = 30 + 31/6      
6      800         0            0            15            m3 + m2 + m1/15 = 30 + 31 + 28/15
7      500         10           10           30            (m3/10) = 30/10 = 3  
8      10          0            0            0             10(age_days)
9      500         0            0            0             m3+m2+m1+1 = 90

     

I am facing issue with dynamically defining m3, m2 and m1 based on the current month.



Solution 1:[1]

Here is one way to do it (as of this answer, current month is April 2022):

from calendar import monthrange
from datetime import datetime

m3, m2, m1 = (
    monthrange(datetime.now().year, datetime.now().month - i)[1] for i in range(0, 3)
)

print(m3)  # 30 [days in April]
print(m2)  # 31 [days in March]
print(m1)  # 28 [days in February]

If you need to extend to 12 months, in order to deal with years cut-off, you can do this:

current_year = datetime.now().year
current_month = datetime.now().month

m12, m11, m10, m9, m8, m7, m6, m5, m4, m3, m2, m1 = [
    monthrange(current_year, current_month - i)[1] for i in range(0, current_month)
] + [monthrange(current_year - 1, 12 - i)[1] for i in range(0, 12 - current_month)]

print(m5)  # 30 [days in September 2021]

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1