Please help make the following pandas dataframe code vectorized/ faster, it's very slow.
I have the below code, which works exactly as I want. It takes domains with lots of subdomains & normalizes them to just the hostname + TLD.
I can't find any vectorization examples using if-else
statements.
import pandas as pd
import time
#import file into dataframe
start = time.time()
path = "Desktop/dom1.csv"
df = pd.read_csv(path, delimiter=',', header='infer', encoding = "ISO-8859-1")
#strip out all ---- values
df2 = df[((df['domain'] != '----'))]
#extract only 2 columns from dataframe
df3 = df2[['domain', 'web.optimisedsize']]
#define tld and cdn lookup lists
tld = ['co.uk', 'com', 'org', 'gov.uk', 'co', 'net', 'news', 'it', 'in' 'es', 'tw', 'pe', 'io', 'ca', 'cat', 'com.au',
'com.ar', 'com.mt', 'com.co', 'ws', 'to', 'es', 'de', 'us', 'br', 'im', 'gr', 'cc', 'cn', 'org.uk', 'me', 'ovh', 'be',
'tv', 'tech', '..', 'life', 'com.mx', 'pl', 'uk', 'ru', 'cz', 'st', 'info', 'mobi', 'today', 'eu', 'fi', 'jp', 'life',
'1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'earth', 'ninja', 'ie', 'im', 'ai', 'at', 'ch', 'ly', 'market', 'click',
'fr', 'nl', 'se']
cdns = ['akamai', 'maxcdn', 'cloudflare']
#iterate through each row of the datafrme and split each domain at the dot
for row in df2.itertuples():
index = df3.domain.str.split('.').tolist()
cleandomain = []
#iterate through each of the split domains
for x in index:
#if it isn't a string, then print the value directly in the cleandomain list
if not isinstance(x, str):
cleandomain.append(str(x))
#if it's a string that encapsulates numbers, then it's an IP
elif str(x)[-1].isnumeric():
try:
cleandomain.append(str(x[0])+'.'+str(x[1])+'.*.*')
except IndexError:
cleandomain.append(str(x))
#if its in the CDN list, take a subdomain as well
elif len(x) > 3 and str(x[len(x)-2]).rstrip() in cdns:
try:
cleandomain.append(str(x[len(x)-3])+'.'+str(x[len(x)-2])+'.'+str(x[len(x)-1]))
except IndexError:
cleandomain.append(str(x))
elif len(x) > 3 and str(x[len(x)-3]).rstrip() in cdns:
try:
cleandomain.append(str(x[len(x)-4])+'.'+str(x[len(x)-3])+'.'+str(x[len(x)-2])+'.'+ str(x[len(x)-1]))
except IndexError:
cleandomain.append(str(x))
#if its in the TLD list, do this
elif len(x) > 2 and str(x[len(x)-2]).rstrip()+'.'+ str(x[len(x)-1]).rstrip() in tld:
try:
cleandomain.append(str(x[len(x)-3])+'.'+str(x[len(x)-2])+'.'+ str(x[len(x)-1]))
except IndexError:
cleandomain.append(str(x))
elif len(x) > 2 and str(x[len(x)-1]) in tld:
try:
cleandomain.append(str(x[len(x)-2])+'.'+ str(x[len(x)-1]))
except IndexError:
cleandomain.append(str(x))
#if its not in the TLD list, do this
else:
cleandomain.append(str(x))
#add the column to the dataframe
df3['newdomain2']=cleandomain
se = pd.Series(cleandomain)
df3['newdomain2'] = se.values
#select only the new domain column & usage
df4 = df3[['newdomain2', 'web.optimisedsize']]
#group by
df5 = df4.groupby(['newdomain2'])[['web.optimisedsize']].sum()
#sort
df6 = df5.sort_values(['web.optimisedsize'], ascending=["true"])
end = time.time()
print(df6)
print(end-start)
My input is this DF:
In [4]: df
Out[4]:
Domain Use
0 graph.facebook.com 4242
1 news.bbc.co.uk 23423
2 news.more.news.bbc.co.uk 234432
3 profile.username.co 235523
4 offers.o2.co.uk 235523
5 subdomain.pyspark.org 2325
6 uds.data.domain.net 23523
7 domain.akamai.net 23532
8 333.333.333.333 3432324
During, the index splits it to this:
[['graph', 'facebook', 'com'], ['news', 'bbc' .....
I then append the new domain to the original dataframe as a new column. This then gets grouped by + summed to create the final dataframe.
In [10]: df
Out[10]:
Domain Use newdomain
0 graph.facebook.com 4242 facebook.com
1 news.bbc.co.uk 23423 bbc.co.uk
2 news.more.news.bbc.co.uk 234432 bbc.co.uk
3 profile.username.co 235523 username.co