File size: 8,512 Bytes
85d2c7e
 
 
 
 
 
 
 
e015ebb
85d2c7e
 
 
 
 
4bae411
85d2c7e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4bae411
85d2c7e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f7bb281
85d2c7e
 
4bae411
85d2c7e
 
 
 
 
 
 
 
 
 
f7bb281
85d2c7e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f7bb281
85d2c7e
 
 
 
 
 
 
 
f7bb281
85d2c7e
 
 
 
 
 
 
 
 
 
 
 
f7bb281
 
85d2c7e
 
 
 
 
 
 
 
 
 
 
f7bb281
85d2c7e
 
 
 
 
 
2d928fb
 
 
 
 
 
 
 
 
 
 
85d2c7e
 
2d928fb
 
 
 
 
 
 
 
 
 
 
85d2c7e
2d928fb
 
 
 
 
 
 
 
 
 
 
 
85d2c7e
2d928fb
 
 
 
 
 
 
 
 
 
 
 
 
85d2c7e
2d928fb
5949d90
 
 
85d2c7e
5949d90
 
85d2c7e
 
 
 
 
 
 
 
 
 
f4e26b8
e015ebb
85d2c7e
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
from sklearn.preprocessing import MinMaxScaler
import warnings
warnings.filterwarnings("ignore")
import plotly.graph_objects as go
from utilities_with_panel import (channel_name_formating)
## reading input data
df= pd.read_csv('response_curves_input_file.csv')
df.dropna(inplace=True)
df['Date'] = pd.to_datetime(df['Date'])
df.reset_index(inplace=True)
import random
channel_cols = [
 'Broadcast TV',
 'Cable TV',
 'Connected & OTT TV',
 'Display Prospecting',
 'Display Retargeting',
    'Video',
 'Social Prospecting',
 'Social Retargeting',
 'Search Brand',
 'Search Non-brand',
 'Digital Partners',
 'Audio',
 'Email']
spend_cols = [
'tv_broadcast_spend', 
'tv_cable_spend',
    'stream_video_spend', 
    'disp_prospect_spend', 
    'disp_retarget_spend',
       'olv_spend', 
        'social_prospect_spend', 
        'social_retarget_spend',
       'search_brand_spend', 
    'search_nonbrand_spend', 
    'cm_spend',
       'audio_spend',
        'email_spend']
prospect_cols = [
        'Broadcast TV_Prospects',
       'Cable TV_Prospects', 
    'Connected & OTT TV_Prospects', 
       'Display Prospecting_Prospects', 
    'Display Retargeting_Prospects',
    'Video_Prospects',
       'Social Prospecting_Prospects', 
    'Social Retargeting_Prospects',
       'Search Brand_Prospects', 
    'Search Non-brand_Prospects',
       'Digital Partners_Prospects',
    'Audio_Prospects', 
    'Email_Prospects']

def hill_equation(x, Kd, n):
    return x**n / (Kd**n + x**n)


def hill_func(x_data,y_data,x_minmax,y_minmax):
    # Fit the Hill equation to the data
    initial_guess = [1, 1]  # Initial guess for Kd and n
    params, covariance = curve_fit(hill_equation, x_data, y_data, p0=initial_guess,maxfev = 1000)

    # Extract the fitted parameters
    Kd_fit, n_fit = params
    

    # Generate y values using the fitted parameters
    y_fit = hill_equation(x_data, Kd_fit, n_fit)

    x_data_inv = x_minmax.inverse_transform(np.array(x_data).reshape(-1,1))
    y_data_inv = y_minmax.inverse_transform(np.array(y_data).reshape(-1,1))
    y_fit_inv = y_minmax.inverse_transform(np.array(y_fit).reshape(-1,1))

#     # Plot the original data and the fitted curve
#     plt.scatter(x_data_inv, y_data_inv, label='Actual Data')
#     plt.scatter(x_data_inv, y_fit_inv, label='Fit Data',color='red')
#     # plt.line(x_data_inv, y_fit_inv, label=f'Fitted Hill Equation (Kd={Kd_fit:.2f}, n={n_fit:.2f})', color='red')
#     plt.xlabel('Ligand Concentration')
#     plt.ylabel('Fraction of Binding')
#     plt.title('Fitting Hill Equation to Data')
#     plt.legend()
#     plt.show()

    return y_fit,y_fit_inv,Kd_fit, n_fit

def data_output(channel,X,y,y_fit_inv,x_ext_data,y_fit_inv_ext): 
    fit_col = 'Fit_Data_'+channel
    plot_df = pd.DataFrame()
   
    plot_df[f'{channel}_Spends'] = X
    plot_df[f'{channel}_Prospects'] = y
    plot_df['Date'] = df['Date']
    plot_df['MAT'] = df['MAT']
    
    

    y_fit_inv_v2 = []
    for i in range(len(y_fit_inv)):
        y_fit_inv_v2.append(y_fit_inv[i][0])
        
    plot_df[fit_col] = y_fit_inv_v2
    
#     adding extra data

    y_fit_inv_v2_ext = []
    for i in range(len(y_fit_inv_ext)):
        y_fit_inv_v2_ext.append(y_fit_inv_ext[i][0])
    
#     # print(x_ext_data)
    ext_df = pd.DataFrame()
    ext_df[f'{channel}_Spends'] = x_ext_data
    ext_df[f'{channel}_Prospects'] = y_fit_inv_v2_ext
    ext_df[fit_col] = y_fit_inv_v2_ext
    
    ext_df['Date'] =  [
                    np.datetime64('1950-01-01'),
                    np.datetime64('1950-06-15'),
                    np.datetime64('1950-12-31')
                ]

    ext_df['MAT'] = ["ext","ext","ext"]
    
    # # print(ext_df.columns)
    plot_df= plot_df.append(ext_df)
    return plot_df

def input_data(df,spend_col,prospect_col):  
    X = np.array(df[spend_col].tolist())
    y = np.array(df[prospect_col].tolist())

    x_minmax = MinMaxScaler()
    x_scaled = x_minmax.fit_transform(df[[spend_col]])
    x_data = []
    for i in range(len(x_scaled)):
        x_data.append(x_scaled[i][0])

    y_minmax = MinMaxScaler()
    y_scaled =  y_minmax.fit_transform(df[[prospect_col]])
    y_data = []
    for i in range(len(y_scaled)):
        y_data.append(y_scaled[i][0])

    return X,y,x_data,y_data,x_minmax,y_minmax

def extend_s_curve(x_max,x_minmax,y_minmax, Kd_fit, n_fit):
    # # print(x_max)
    x_ext_data = [x_max*1.2,x_max*1.3,x_max*1.5]
#     x_ext_data = [1500000,2000000,2500000]
#     x_ext_data = [x_max+100,x_max+200,x_max+5000]
    x_scaled = x_minmax.transform(pd.DataFrame(x_ext_data))
    x_data = []
    for i in range(len(x_scaled)):
        x_data.append(x_scaled[i][0])
        
    # # print(x_data)
    y_fit = hill_equation(x_data, Kd_fit, n_fit)
    y_fit_inv = y_minmax.inverse_transform(np.array(y_fit).reshape(-1,1))
    
    return x_ext_data,y_fit_inv
    
def fit_data(spend_col,prospect_col,channel):
    ### getting k and n parameters
    temp_df = df[df[spend_col]>0]
    temp_df.reset_index(inplace=True)

    X,y,x_data,y_data,x_minmax,y_minmax = input_data(temp_df,spend_col,prospect_col)
    y_fit, y_fit_inv, Kd_fit, n_fit = hill_func(x_data,y_data,x_minmax,y_minmax)
    # # print('k: ',Kd_fit)
    # # print('n: ', n_fit)
    
    ##### extend_s_curve
    x_ext_data,y_fit_inv_ext=  extend_s_curve(temp_df[spend_col].max(),x_minmax,y_minmax, Kd_fit, n_fit)
    
    plot_df = data_output(channel,X,y,y_fit_inv,x_ext_data,y_fit_inv_ext)
    return plot_df

plotly_data = fit_data(spend_cols[0],prospect_cols[0],channel_cols[0])
plotly_data.tail()

for i in range(1,13):
    # print(i)
    pdf =  fit_data(spend_cols[i],prospect_cols[i],channel_cols[i])
    plotly_data = plotly_data.merge(pdf,on = ["Date","MAT"],how = "left")
    
def response_curves(channel,chart_typ):
    if chart_typ == 'View Scattered Plot':
        mode_f1 = "markers"
        # Initialize the Plotly figure
        fig = go.Figure()
    
        x_col = channel+"_Spends"
        y_col = channel+"_Prospects"
        fig.add_trace(go.Scatter(
            x=plotly_data.sort_values(by=x_col, ascending=True)[x_col],
            y=plotly_data.sort_values(by=x_col, ascending=True)[y_col],
            mode=mode_f1,
            name=x_col.replace('_Spends', '')
        ))
    elif chart_typ == 'View Line Plot':
        mode_f1 = "lines"
        # Initialize the Plotly figure
        fig = go.Figure()
    
        x_col = channel+"_Spends"
        y_col = 'Fit_Data_'+channel
        fig.add_trace(go.Scatter(
            x=plotly_data.sort_values(by=x_col, ascending=True)[x_col],
            y=plotly_data.sort_values(by=x_col, ascending=True)[y_col],
            mode=mode_f1,
            name=x_col.replace('_Spends', '')
        ))
    else:
        mode_f1 = "markers"
        # Initialize the Plotly figure
        fig = go.Figure()
    
        x_col = channel+"_Spends"
        y_col = channel+"_Prospects"
        fig.add_trace(go.Scatter(
            x=plotly_data.sort_values(by=x_col, ascending=True)[x_col],
            y=plotly_data.sort_values(by=x_col, ascending=True)[y_col],
            mode=mode_f1,
            name=x_col.replace('_Spends', '')
        ))

        # mode_f1 = "lines+markers"
        mode_f1 = "lines"
        # Initialize the Plotly figure
        # fig = go.Figure()
    
        x_col = channel+"_Spends"
        y_col = 'Fit_Data_'+channel
        fig.add_trace(go.Scatter(
            x=plotly_data.sort_values(by=x_col, ascending=True)[x_col],
            y=plotly_data.sort_values(by=x_col, ascending=True)[y_col],
            mode=mode_f1,
            name=x_col.replace('_Spends', '')
        ))

    
    plotly_data2 = plotly_data[plotly_data[x_col].isnull()==False]
    # import steamlit as st
    # st.dataframe()    
    fig.add_trace(go.Scatter(
        x=plotly_data2[plotly_data2['Date'] == plotly_data2['Date'].max()][x_col],
        y=plotly_data2[plotly_data2['Date'] == plotly_data2['Date'].max()][y_col],
        mode='markers',
        marker=dict(
        size=13  # Adjust the size value to make the markers larger or smaller
        , color = 'green'
        ),
        name="Current Spends"
    ))

    # Update layout with titles
    fig.update_layout(
        width=700, height=500,
        title=channel_name_formating(channel)+' Response Curve',
        xaxis_title='Weekly Spends',
        yaxis_title='Prospects'
    )

    # Show the figure
    return fig