如何使用Pandas和SciKitLearn堆栈提高Python脚本的性能?

时间:2017-10-14 03:28:38

标签: python pandas data-science

我使用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:将我的任务与JobLibhttps://pythonhosted.org/joblib/parallel.html)并行化,将我的脚本虚拟速度缩短了3-4倍:)

Parallel(n_jobs=4)(delayed(insert_or_read_scores_on_db)(city['name']) for city in cities)

仍在寻找改进,但

1 个答案:

答案 0 :(得分:0)

我有2条建议可能对您有所帮助。

1)在第二步中,您正在使用适用于列的每个单元格的数据帧应用功能。如果以某种方式你可以编写for循环来做到这一点,你可以使用python Numba库,它以并行的方式着名。您可以使用for循环创建一个函数,在该函数中,您可以为多核CPU提供并行工作的装饰器@jit。你需要从numba import jit

做 2)我在课程中看过华盛顿大学教授的一个视频,他教授如何使用map reduce算法来做两个可以并行运行的表的JOIN。这样,如果它并行运行,你也可以快速加入。