访问和操作pandas df的最有效方法是什么

时间:2017-05-06 20:14:21

标签: python pandas

我正在开发基于代理的建模项目,并且有一个代表景观的800x800网格。此网格中的每个单元格都分配了某些变量。其中一个变量是“植被”(即该细胞具有的功能类型)。我的数据名称如下:

Vegetation variables

在访问此数据框之前,会为每个单元格分配一个landscape_type。然后我循环遍历800x800网格中的每个单元格并分配更多变量,因此,例如,如果单元格1是landscape_type 4,我需要访问上面的数据框,为min和max_species_percent之间的每个functional_type生成一个随机数,并且然后将该landscape_type的所有变量(即pollen_loading,succession_time等等)分配给该单元格,但是,如果随机数的cumsum是< 100,我从下一个landscape_type中获取function_types(所以在这个例子中,我会向下移动到landscape_type 3),这一直持续到我接近100的cumsum。

我让这个过程按照需要运行,但速度非常慢 - 你可以想象,有成千上万的任务!到目前为止我这样做(self.model.veg_data是上面的df):

    def create_vegetation(self, landscape_type):

    if landscape_type == 4:
        veg_this_patch = self.model.veg_data[self.model.veg_data['landscape_type'] <= landscape_type].copy()
    else:
        veg_this_patch = self.model.veg_data[self.model.veg_data['landscape_type'] >= landscape_type].copy()

    veg_this_patch['veg_total'] = veg_this_patch.apply(lambda x: randint(x["min_species_percent"],
                                          x["max_species_percent"]), axis=1)
    veg_this_patch['cum_sum_veg'] = veg_this_patch.veg_total.cumsum()
    veg_this_patch = veg_this_patch[veg_this_patch['cum_sum_veg'] <= 100]
    self.vegetation = veg_this_patch

我确信有更有效的方法可以做到这一点。这个过程将不断重复,随着模型的进展,landscape_types会发生变化,即3变为4.所以它必不可少的变得越来越快!谢谢。

根据评论:编辑。

创建横向对象的循环如下:

            for agent, x, y in self.grid.coord_iter():
        # check that patch is land
        if self.landscape.elevation[x,y] != -9999.0:
            elevation_xy = int(self.landscape.elevation[x, y])

            # calculate burn probabilities based on soil and temp
            burn_s_m_p = round(2-(1/(1 + (math.exp(- (self.landscape.soil_moisture[x, y] * 3)))) * 2),4)
            burn_s_t_p = round(1/(1 + (math.exp(-(self.landscape.soil_temp[x, y] * 1))) * 3), 4)

            # calculate succession probabilities based on soil and temp
            succ_s_m_p = round(2 - (1 / (1 + (math.exp(- (self.landscape.soil_moisture[x, y] * 0.5)))) * 2), 4)
            succ_s_t_p = round(1 / (1 + (math.exp(-(self.landscape.soil_temp[x, y] * 1))) * 0.5), 4)

            vegetation_typ_xy = self.landscape.vegetation[x, y]

            time_colonised_xy = self.landscape.time_colonised[x, y]
            is_patch_colonised_xy = self.landscape.colonised[x, y]

            # populate landscape patch with values
            patch = Landscape((x, y), self, elevation_xy, burn_s_m_p, burn_s_t_p, vegetation_typ_xy,
                              False, time_colonised_xy, is_patch_colonised_xy, succ_s_m_p, succ_s_t_p)
            self.grid.place_agent(patch, (x, y))
            self.schedule.add(patch)

然后,在对象本身中,我调用create_vegetation函数来添加上面df中的functional_types。此循环中的其他所有内容都来自不同的数据集,因此不相关。

1 个答案:

答案 0 :(得分:0)

您需要在矢量化预处理步骤中提取尽可能多的计算。例如,在您的800x800循环中,您有:

burn_s_m_p = round(2-(1/(1 + (math.exp(- (self.landscape.soil_moisture[x, y] * 3)))) * 2),4)

在初始化期间执行一次,而不是执行此行800x800次:

burn_array = np.round(2-(1/(1 + (np.exp(- (self.landscape.soil_moisture * 3)))) * 2),4)

现在在你的循环中它只是:

burn_s_m_p = burn_array[x, y]

将此技术应用于其余类似的行。