def city_check(test):
test=str(test)
for ele in city: #city is a list containing 2200 city names.
ele=str(ele)
result = re.findall('\b'+ele+'\b', test, flags=re.IGNORECASE)
if len(result)>0:
return ele
return "Not Found"
df['city']=df['address_line_1'].apply(city_check) #df has 2.5 million rows
为什么要花这么长时间?我怎样才能让它更快?
为什么要花这么长时间?:
您对所有250万个条目调用该函数。每次你这样做,你都会在2500个城市中循环(早期回报很少见,所以我忽略了它们(。所以你调用re.findall()
2 500 000*2 500=5 500 000 000次。
仅仅增加+1亿次,我的笔记本电脑就花了大约7秒。这将超过6分钟55亿次,我只测试了一个最快的操作,而你使用的操作要复杂得多。
怎样才能更快?:
您的大部分时间都由regex函数使用。这里不需要regex,可以使用"sub" in "string"
,这要快得多(在我刚刚做的一个小测试中,它大约快了15倍
if city.lower() in test.lower(): # in reply to some comments: yes that can lead to wrong results, but keep reading
...
您可以通过不每次调用.lower()
来进行更多优化。在执行.apply()
之前,请创建一个所有小写城市名称的列表(并在每个城市名称的开头和结尾添加类似环境的空格,以解决错误的结果问题(,因此您只需要执行一次,并在函数开始时将test
转换为小写。
def city_check(test):
test=str(test).lower()
for ele in cityLowerNames:
if ele in test:
return ele
return "Not Found"
作为进一步的优化,你可以并行运行循环,但由于你只循环了2500个项目,所以当你每次启动额外的线程时,它不会那么有效,甚至可能更糟。因此,如果您尝试并行执行,请确保启动线程一次并保持其运行。也许你可以用它快4倍,这取决于需要多少额外的逻辑。
如果只需要通过函数返回第一个匹配项,我建议使用re.search
或re.match
进行此regex操作。就处理能力而言,re.findall
的成本相当高,尤其是考虑到您正在处理的大量行。
关于不同正则表达式函数的详细信息:此处
可以通过使用像multiprocessing
这样的多处理模块来进一步提高该操作的速度。此处的文档
然而,这将取决于你需要多久运行一次这个函数,以及它是否值得开发时间!
我试过这个:
import pandas as pd
import numpy as np
d = {'address_line_1': ['93346 INDIA BULLS 2ND FLOOR GARND MALL GT ROAD JAL... 1', 'None', 'None', '5 93346 U WB FAIRLAND COLONY FGC ROAD JALANDHAR PUNJAB 1', 'None', 'None', '6 129128 D 501 WHESPERING PALMS XCLUSIVE AKURLI ROAD LO... 1', 'None', 'None', '7 62321 GUT NO: BUILDING NAME: BUILDING NO 130 HOUSE N...1', 'None', 'None', '8 147383 D NO 20 1 272 RAMALAYAM STREET MANGALAM ROAD']}
df = pd.DataFrame(data=d)
city=list(['akurli','ramalayam'])
df['city'] = df['address_line_1'].apply(lambda x: [item for item in str(x).lower().split() if item in city])
df['city'] = df['city'].str[0]
df
我得到
address_line_1 city
0 93346 INDIA BULLS 2ND FLOOR GARND MALL GT ROAD... NaN
1 None NaN
2 None NaN
3 5 93346 U WB FAIRLAND COLONY FGC ROAD JALANDHA... NaN
4 None NaN
5 None NaN
6 6 129128 D 501 WHESPERING PALMS XCLUSIVE AKURL... akurli
7 None NaN
8 None NaN
9 7 62321 GUT NO: BUILDING NAME: BUILDING NO 130... NaN
10 None NaN
11 None NaN
12 8 147383 D NO 20 1 272 RAMALAYAM STREET MANGAL... ramalayam
现在,这可能不是最有效的方法,但我可以很快在大的df上复制它:
dff = pd.concat([df]*1000000, ignore_index=True)
dff.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 13000000 entries, 0 to 12999999
Data columns (total 1 columns):
# Column Dtype
--- ------ -----
0 address_line_1 object
dtypes: object(1)
memory usage: 99.2+ MB
%%time
dff['city'] = dff['address_line_1'].apply(lambda x: [item for item in str(x).lower().split() if item in city])
CPU times: user 19.7 s, sys: 856 ms, total: 20.5 s
Wall time: 20.5 s