Одна из проблем заключается в том, что на каждой выполняемой итерации у вас есть index = df3.domain.str.split('.').tolist()
.Когда я помещаю эту строку вне цикла, вычисление происходит в 2 раза быстрее.587 мс против 1,1 с.
Я тоже считаю, что ваш код неверен.Вы не используете переменную row
и вместо нее используете index
.И когда вы повторяете индекс, один элемент всегда является списком.Так что if not isinstance(x, str)
всегда верно.(Вы можете увидеть это в выводе line_debugger ниже)
Строковые операции, как правило, не векторизованы.Даже нотация .str
на самом деле представляет собой цикл Python.
А вот вывод инструмента line_debugger в записной книжке Jupyter: Инициализация (f - это функция, обернутая вокруг кода):
%load_ext line_profiler
%lprun -f f f(df2, df3)
Вывод:
Total time: 1.82219 s
File: <ipython-input-8-79f01a353d31>
Function: f at line 1
Line # Hits Time Per Hit % Time Line Contents
==============================================================
1 def f(df2,df3):
2 1 8093.0 8093.0 0.2 index = df3.Domain.str.split('.').tolist()
3 #iterate through each row of the datafrme and split each domain at the dot
4 901 11775.0 13.1 0.2 for row in df2.itertuples():
5
6 900 26241.0 29.2 0.5 cleandomain = []
7 #iterate through each of the split domains
8 810900 971082.0 1.2 18.8 for x in index:
9 #if it isn't a string, then print the value directly in the cleandomain list
10 810000 1331253.0 1.6 25.8 if not isinstance(x, str):
11 810000 2819163.0 3.5 54.6 cleandomain.append(str(x))
12 #if it's a string that encapsulates numbers, then it's an IP
13 elif str(x)[-1].isnumeric():
14 try:
15 cleandomain.append(str(x[0])+'.'+str(x[1])+'.*.*')
16 except IndexError:
17 cleandomain.append(str(x))
18 #if its in the CDN list, take a subdomain as well
19 elif len(x) > 3 and str(x[len(x)-2]).rstrip() in cdns:
20 try:
21 cleandomain.append(str(x[len(x)-3])+'.'+str(x[len(x)-2])+'.'+str(x[len(x)-1]))
22 except IndexError:
23 cleandomain.append(str(x))
24 elif len(x) > 3 and str(x[len(x)-3]).rstrip() in cdns:
25 try:
26 cleandomain.append(str(x[len(x)-4])+'.'+str(x[len(x)-3])+'.'+str(x[len(x)-2])+'.'+ str(x[len(x)-1]))
27 except IndexError:
28 cleandomain.append(str(x))
29 #if its in the TLD list, do this
30 elif len(x) > 2 and str(x[len(x)-2]).rstrip()+'.'+ str(x[len(x)-1]).rstrip() in tld:
31 try:
32 cleandomain.append(str(x[len(x)-3])+'.'+str(x[len(x)-2])+'.'+ str(x[len(x)-1]))
33 except IndexError:
34 cleandomain.append(str(x))
35 elif len(x) > 2 and str(x[len(x)-1]) in tld:
36 try:
37 cleandomain.append(str(x[len(x)-2])+'.'+ str(x[len(x)-1]))
38 except IndexError:
39 cleandomain.append(str(x))
40 #if its not in the TLD list, do this
41 else:
42 cleandomain.append(str(x))
Мой код:
Подготовка данных:
from io import StringIO
import pandas as pd
#import file into dataframe
TESTDATA=StringIO("""Domain,Use
graph.facebook.com, 4242
news.bbc.co.uk, 23423
news.more.news.bbc.co.uk, 234432
profile.username.co, 235523
offers.o2.co.uk, 235523
subdomain.pyspark.org, 2325
uds.data.domain.net, 23523
domain.akamai.net, 23532
333.333.333.333,3432324
""")
df=pd.read_csv(TESTDATA)
df["Domain"] = df.Domain.str.strip()
df = pd.concat([df]*100)
df2 = df
#extract only 2 columns from dataframe
df3 = df2
#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']
Время в блокноте Юпитера:
%%timeit
index = df3.Domain.str.split('.').tolist()
#iterate through each row of the datafrme and split each domain at the dot
for row in df2.itertuples():
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))