【问题标题】:More efficient way than row by row calculation of Pandas Dataframe比 Pandas Dataframe 的逐行计算更有效的方法
【发布时间】:2018-10-03 11:16:43
【问题描述】:

在我当前的项目中,我正在对森林清单数据进行数据分析,并通过最大似然估计将统计分布拟合到数据中。

我为每个所需的数据子集计算每个数据集的结果,并返回估计的分布参数和我需要的其他指标,然后将它们全部存储在 pandas 数据框中。

到目前为止,我在一个大的 for 循环中遍历每个数据子集,然后将结果逐行分配给数据框。

我想知道有没有更有效的方法来做到这一点?我也不想拥有大量数据副本,因为我经常拥有大约一百万个数据点。

我用人工数据创建了一个非常简化的例子,没有最大似然估计,但这显示了基本结构

import pandas as pd
import scipy as sp

import numpy.random as sprd

def Gen_UniformDist(seed=5, size=1000000):
    """ Create a set of random numbers uniformly distributed between 0 and 1 """
    sprd.seed(seed)    
    return sprd.uniform(size=size)

# Generate some test data
dataSet = Gen_UniformDist()

# Create an array of truncation vales
truncValue_arr = sp.linspace(0., 0.9, 20)

df_Output = pd.DataFrame(index=truncValue_arr, columns=['mean', 'NumObs'])

for i, truncValue in enumerate(truncValue_arr):
    # Truncate the data using the truncation value
    truncated_DataSet = dataSet[ dataSet >= truncValue]

    # In my real code the function here is more complex max likelihood 
    # rather than simple mean used for simplicity here
    mean = sp.mean(truncated_DataSet)

    numObs = len(truncated_DataSet)

    # Real code would calculate more than 2 values for each row
    df_Output.iloc[i] = [mean, numObs]

我想要做的是在没有 for 循环的情况下有效地填充数据帧,但也要避免周围有大量数据副本。这可能吗?

【问题讨论】:

  • 如果您不想要大量副本,则需要将所有数据volcate到字典中,对字典执行操作,然后删除旧数据并将字典划分为行重新生成整个内容.您还可以在 django 上使用诸如批量创建方法之类的方法来生成 sql 模型,然后再生成另一个数据帧

标签: python pandas performance


【解决方案1】:

您的算法有两个方面可以立即优化:

  1. 用列表理解替换 for 循环。
  2. 与其重复调用iloc,不如构建一个元组列表并直接提供给pd.DataFrame

这是一些伪代码:

def return_values(data):
    return sp.mean(data), len(data.index)

L = [return_values(dataSet[dataSet >= truncValue]) for truncValue in truncValue_arr]

df = pd.DataFrame(data=L, index=truncValue_arr, columns=['mean', 'NumObs'])

您可以通过重构每个循环中出现的dataSet >= truncValue 来进一步优化。考虑以下几点:

s = pd.Series([1, 2, 3, 4, 5])
vals = np.array([2, 4])

s[:, None] > vals

array([[False, False],
       [False, False],
       [ True, False],
       [ True, False],
       [ True,  True]], dtype=bool)

因此,您可以执行以下操作:

mask = np.array(dataset)[:, None] >= np.array(truncValue_arr)

L = [return_values(dataset.loc[mask[:, i]]) \
     for i, truncValue in enumerate(truncValue_arr)]

【讨论】:

  • 感谢您的回复。我对这三种解决方案进行了计时,发现你建议的最后一个(使用面具)实际上是最慢的,但你的第一个最快。最快的也是最简洁的代码并且使用更少的内存。
  • @JMoore1805,是的,这可能是系统特定的,例如您的系统拥有多少内存与 CPU 速度,当然还有dataSettruncValue_arr 的相对尺寸。
猜你喜欢
  • 2022-01-07
  • 2016-06-21
  • 1970-01-01
  • 2018-11-22
  • 1970-01-01
  • 1970-01-01
  • 2012-07-01
  • 1970-01-01
  • 2021-11-12
相关资源
最近更新 更多