我使用Python和SciKitLearn堆栈创建了一个匹配巴西城市之间气候数据的脚本。目前,我使用带有60M +条目的气候集合的MongoDB,以及Pandas来查询和加入这些表格。
我将每个巴西城市的气候数据与一个简单的算法相互比较,为每对城市生成最终得分。
问题是它需要太长时间(每对11秒)。这真的很慢,因为我希望得到所有12M +可能组合的得分。我怎样才能让它更快?以下是相关代码:
与MongoDB连接(几乎是即时):
client = MongoClient('localhost', 27017)
db = client.agricredit_datafetcher_development
获取气候数据(快速,但不是即时):
base_weather_data = list(db.meteo_data_weather_data.find({'weather_station_id': ObjectId(base_weather_station['_id'])}))
target_weather_data = list(db.meteo_data_weather_data.find({'weather_station_id': ObjectId(target_weather_station['_id'])}))
return {'base_dataframe': pd.DataFrame(base_weather_data),
'target_dataframe': pd.DataFrame(target_weather_data)}
从嵌入式(嵌套)Mongo集合中获取数据(慢):
base_dataframe = dataframes['base_dataframe'].set_index('analysis_date')['weather_forecast'].apply(pd.Series)
target_dataframe = dataframes['target_dataframe'].set_index('analysis_date')['weather_forecast'].apply(pd.Series)
查询删除空值并加入DataFrames(快速,但不是即时):
available_forecast_data = base_dataframe[base_dataframe['weather_forecast'] > 0][['weather_forecast']]
to_be_compared_data = target_dataframe[target_dataframe['weather_forecast'] > 0][['weather_forecast']]
join_dataframe = available_forecast_data.join(to_be_compared_data, how='inner', lsuffix='_base', rsuffix='_target')
然后我应用评分算法(非常快,只是求和和平均值),然后将其插入我的Mongo数据库。
如何改进我的代码?
以下是一些要点:
我非常确定我是否能够处理嵌入式MongoDB数据(第三步),而无需使用pd.Series
方法创建新的DataFrame。我已经尝试了json.normalize
我的Mongo集合,然后将其转换为数据帧,但它也很慢,而且当我这样做时,一些数据会被搞砸。
瓶颈在于所描述的步骤。所有其他步骤(例如评分算法)都是即时的;
我依靠Pandas进行查询,分组和创建Dataframes。这可以吗?我很想试试Mongo Aggregation Framework,看看我是否有任何改进。值得吗?
Hadoop / Spark是否有办法改善这一点?我很难理解他们在数据科学项目中的角色;
编辑:第三点解决了!使用Mongo Aggregations而不是将pd.Series
方法应用于数据框:
pipeline = [
{"$match" : {"weather_station_id": ObjectId(weather_station_id)}},
{"$project": {
'analysis_date': "$analysis_date",
'rainfall': "$rainfall.rainfall",
'agricultural_drought': "$rainfall.agricultural_drought",
'weather_forecast': "$weather_forecast.med_temp"
}
}
]
现在每对城市需要大约1.2秒。但我觉得我仍然可以改善这一点......现在瓶颈在于weather_data
查询。但它被编入索引,有没有办法让它更快?
编辑2:将我的任务与JobLib
(https://pythonhosted.org/joblib/parallel.html)并行化,将我的脚本虚拟速度缩短了3-4倍:):
Parallel(n_jobs=4)(delayed(insert_or_read_scores_on_db)(city['name']) for city in cities)
仍在寻找改进,但
答案 0 :(得分:0)
我有2条建议可能对您有所帮助。
1)在第二步中,您正在使用适用于列的每个单元格的数据帧应用功能。如果以某种方式你可以编写for循环来做到这一点,你可以使用python Numba库,它以并行的方式着名。您可以使用for循环创建一个函数,在该函数中,您可以为多核CPU提供并行工作的装饰器@jit。你需要从numba import jit
做 2)我在课程中看过华盛顿大学教授的一个视频,他教授如何使用map reduce算法来做两个可以并行运行的表的JOIN。这样,如果它并行运行,你也可以快速加入。