Script 407: New Launch Updates Round 1

Purpose

The Python script automates the updating of campaign statuses, bid strategies, and target CPA values for new launch campaigns based on specific performance metrics.

To Elaborate

The script is designed to manage and update digital marketing campaigns by evaluating their performance metrics. It focuses on campaigns that have been recently launched, adjusting their status, bid strategy, and target cost-per-acquisition (CPA) based on the number of clicks and revenue per click (RPC) they generate. Campaigns with five or more clicks are assessed for their RPC, and those with an RPC below a certain threshold are paused, while others are adjusted to a ‘TargetCpa’ strategy. Campaigns with fewer than five clicks are evaluated based on their cost, with high-cost campaigns being paused. This ensures that marketing budgets are allocated efficiently, optimizing for better performance and return on investment.

Walking Through the Code

  1. Initialization and Setup
    • The script begins by defining constants for column names used in the input data.
    • Temporary columns are created in the input DataFrame to store new values for campaign status, bid strategy, daily budget, maturity, and target CPA.
  2. Data Segmentation
    • The input data is split into two DataFrames: after_fiveDf for campaigns with five or more clicks and before_fiveDf for those with fewer than five clicks.
  3. Campaign Evaluation and Adjustment
    • For after_fiveDf, campaigns with an RPC below 2.75 are paused, while others are set to a ‘TargetCpa’ strategy with adjustments to their target CPA.
    • For before_fiveDf, campaigns with a cost exceeding $50 are paused.
  4. Change Detection and DataFrame Creation
    • The script identifies campaigns with changes in status, bid strategy, or target CPA and creates moreDf and lessDf DataFrames for campaigns with five or more clicks and fewer than five clicks, respectively.
  5. Output Generation
    • The script merges non-empty DataFrames (moreDf and lessDf) to form the final output DataFrame, which contains the updated campaign information.

Vitals

  • Script ID : 407
  • Client ID / Customer ID: 1306925431 / 60269477
  • Action Type: Bulk Upload (Preview)
  • Item Changed: Campaign
  • Output Columns: Account, Campaign, Status, Publisher Bid Strategy, Publisher Target CPA
  • Linked Datasource: M1 Report
  • Reference Datasource: None
  • Owner: Byron Porter (bporter@marinsoftware.com)
  • Created by Byron Porter on 2023-10-24 21:01
  • Last Updated by Byron Porter on 2023-12-06 04:01
> See it in Action

Python Code

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
#
# Update, Status, tCPA, Bid Strategy, and or Campaign Maturity for New Launch Campaigns
#  
#  
#
#
# Author: Byron Porter
# Date: 2023-10-16
#


RPT_COL_CAMPAIGN = 'Campaign'
RPT_COL_ACCOUNT = 'Account'
RPT_COL_CAMPAIGN_STATUS = 'Campaign Status'
RPT_COL_DAILY_BUDGET = 'Daily Budget'
RPT_COL_PUBLISHER_BIDSTRATEGY = 'Publisher Bid Strategy'
RPT_COL_PUBLISHER_TARGETCPA = 'Publisher Target CPA'
RPT_COL_PUB_COST = 'Pub. Cost $'
RPT_COL_REVENUE = 'Revenue $'
RPT_COL_ROAS = 'CLICKS ROAS %'
RPT_COL_RPC = 'Rev./Click $'
RPT_COL_CLICKS = 'Clicks'
RPT_COL_MATURITY = 'Campaign Maturity'
RPT_COL_COST_PER_CONV = 'CLICKS Cost/Conv.'

BULK_COL_ACCOUNT = 'Account'
BULK_COL_CAMPAIGN = 'Campaign'
BULK_COL_STATUS = 'Status'
BULK_COL_DAILY_BUDGET = 'Daily Budget'
BULK_COL_PUBLISHER_TARGETCPA = 'Publisher Target CPA'
BULK_COL_PUBLISHER_BIDSTRATEGY = 'Publisher Bid Strategy'
BULK_COL_MATURITY = 'Campaign Maturity'


#set maturity parameter value so that it can be used in tuple
current_strategy = inputDf[RPT_COL_PUBLISHER_BIDSTRATEGY]

# temp columns to house new values and make sure all values are cleared out
TMP_STATUS = RPT_COL_CAMPAIGN_STATUS + '_'
inputDf[TMP_STATUS] = np.nan

TMP_PUB_STRATEGY = RPT_COL_PUBLISHER_BIDSTRATEGY + '_'
inputDf[TMP_PUB_STRATEGY] = np.nan

TMP_BUDGET = RPT_COL_DAILY_BUDGET + '_'
inputDf[TMP_BUDGET] = np.nan

TMP_MATURITY = RPT_COL_MATURITY + '_'
inputDf[TMP_MATURITY] = np.nan

TMP_TARGETCPA = RPT_COL_PUBLISHER_TARGETCPA + '_'
inputDf[TMP_TARGETCPA] = np.nan

# define temp dataframes
moreDf = pd.DataFrame()
lessDf = pd.DataFrame()

# Check if campaigns have 5 or more clicks
clicks_check = inputDf[RPT_COL_CLICKS] >= 5

# Use check to create DataFrames for campaigns with and without more than 5 clicks during reporting period
after_fiveDf = inputDf.loc[clicks_check, :].copy()
before_fiveDf = inputDf.loc[~clicks_check, :].copy()


# use boolean expressions to set new values based on Rev/Click and spend thresholds
after_fiveDf.loc[after_fiveDf[RPT_COL_RPC] < 2.75, TMP_STATUS] = 'Pause'
after_fiveDf.loc[after_fiveDf[RPT_COL_RPC] < 2.75, TMP_PUB_STRATEGY] = after_fiveDf[RPT_COL_PUBLISHER_BIDSTRATEGY]
after_fiveDf.loc[after_fiveDf[RPT_COL_RPC] < 2.75, TMP_TARGETCPA] = after_fiveDf[RPT_COL_PUBLISHER_TARGETCPA]

after_fiveDf.loc[after_fiveDf[RPT_COL_RPC] >= 2.75, TMP_STATUS] = after_fiveDf[RPT_COL_CAMPAIGN_STATUS]
after_fiveDf.loc[after_fiveDf[RPT_COL_RPC] >= 2.75, TMP_PUB_STRATEGY] = 'TargetCpa'
after_fiveDf.loc[after_fiveDf[RPT_COL_RPC] >= 2.75, TMP_TARGETCPA] = after_fiveDf[RPT_COL_COST_PER_CONV]

before_fiveDf.loc[before_fiveDf[RPT_COL_PUB_COST] > 50, TMP_STATUS] = 'Pause'
before_fiveDf.loc[before_fiveDf[RPT_COL_PUB_COST] > 50, TMP_PUB_STRATEGY] = before_fiveDf[RPT_COL_PUBLISHER_BIDSTRATEGY]
before_fiveDf.loc[before_fiveDf[RPT_COL_PUB_COST] > 50, TMP_TARGETCPA] = before_fiveDf[RPT_COL_PUBLISHER_TARGETCPA]


print("== Current After Dataframe ==", tableize(after_fiveDf))
print("== Current Before Dataframe ==", tableize(before_fiveDf))

# find changed campaigns for campaigns with 5 or more clicks
changed = (after_fiveDf[TMP_STATUS].notnull() & (after_fiveDf[RPT_COL_CAMPAIGN_STATUS] != after_fiveDf[TMP_STATUS])) | \
          (after_fiveDf[TMP_PUB_STRATEGY].notnull() & (after_fiveDf[RPT_COL_PUBLISHER_BIDSTRATEGY] != after_fiveDf[TMP_PUB_STRATEGY])) | \
          (after_fiveDf[TMP_TARGETCPA].notnull() & (after_fiveDf[RPT_COL_PUBLISHER_TARGETCPA] != after_fiveDf[TMP_TARGETCPA]))

if sum(changed) > 0:

    print("== Campaigns with Changed Adj ==", tableize(after_fiveDf.loc[changed]))

    # only select changed rows
    cols = [RPT_COL_ACCOUNT, RPT_COL_CAMPAIGN, TMP_STATUS, TMP_PUB_STRATEGY, TMP_TARGETCPA]
    moreDf = after_fiveDf.loc[ changed, cols ].copy() \
                    .rename(columns = { \
                        TMP_STATUS: BULK_COL_STATUS, \
                        TMP_PUB_STRATEGY: BULK_COL_PUBLISHER_BIDSTRATEGY, \
                        TMP_TARGETCPA: BULK_COL_PUBLISHER_TARGETCPA \
                    })

else:
    
    print("Empty moreDf")
    moreDf = moreDf.iloc[0:0]

# find changed campaigns for campaigns with less than 5 clicks
changed = (before_fiveDf[TMP_STATUS].notnull() & (before_fiveDf[RPT_COL_CAMPAIGN_STATUS] != before_fiveDf[TMP_STATUS])) | \
          (before_fiveDf[TMP_PUB_STRATEGY].notnull() & (before_fiveDf[RPT_COL_PUBLISHER_BIDSTRATEGY] != before_fiveDf[TMP_PUB_STRATEGY])) | \
          (before_fiveDf[TMP_TARGETCPA].notnull() & (before_fiveDf[RPT_COL_PUBLISHER_TARGETCPA] != before_fiveDf[TMP_TARGETCPA]))

if sum(changed) > 0:

    print("== Campaigns with Changed Adj ==", tableize(before_fiveDf.loc[changed]))

    # only select changed rows
    cols = [RPT_COL_ACCOUNT, RPT_COL_CAMPAIGN, TMP_STATUS, TMP_PUB_STRATEGY, TMP_TARGETCPA]
    lessDf = before_fiveDf.loc[ changed, cols ].copy() \
                    .rename(columns = { \
                        TMP_STATUS: BULK_COL_STATUS, \
                        TMP_PUB_STRATEGY: BULK_COL_PUBLISHER_BIDSTRATEGY, \
                        TMP_TARGETCPA: BULK_COL_PUBLISHER_TARGETCPA \
                    })

else:
    
    print("Empty lessDf")
    lessDf = lessDf.iloc[0:0]    

# Merge defined data, exlcuding those that are empty, and print the resulting outputDf
dataframes = [moreDf, lessDf]
non_empty_dataframes = [df for df in dataframes if not df.empty]

if non_empty_dataframes:
    outputDf = pd.concat(non_empty_dataframes)
    print("outputDf", tableize(outputDf))
else:
    print("Empty outputDf")
    outputDf = outputDf.iloc[0:0]

Post generated on 2024-11-27 06:58:46 GMT

comments powered by Disqus