【问题标题】:How to make pd.Dataframe column assignment faster?如何使 pd.Dataframe 列分配更快?
【发布时间】:2018-12-03 09:39:01
【问题描述】:

所以我正在尝试将列添加到现有的数据框,其中大部分是逻辑比较:

def qualitycheck(data, qparams, qid):
    data = data.assign(parameter_set = qid)
    data = data.assign(volume_below_max = (data["volume"] < int(qparams["max_volume"])))
    data = data.assign(volume_trucks_below_max = (data["volume_trucks"]  < int(qparams["max_volume_trucks"])))
    data = data.assign(volume_cars_below_max = (data["volume_cars"] < int(qparams["max_volume_cars"])))
    data = data.assign(volume_diffcheck_ok = diffcheck(data["volume"]))
    data = data.assign(occupancy_below_max = data["occupancy"]  < int(qparams["max_occupancy"]))
    data = data.assign(occupancy_diffcheck_ok = diffcheck(data["occupancy"]))
    data = data.assign(speed_below_max = data["speed"] < int(qparams["max_speed"]))
    data = data.assign(speed_trucks_below_max= data["speed_trucks"]  < int(qparams["max_speed_trucks"]))
    data = data.assign(speed_cars_below_max = data["speed_cars"] < int(qparams["max_speed_cars"]))
    data = data.assign(speed_diffcheck_ok = diffcheck(data["speed"]))
    data = data.assign(volume_speed_plausible = q_v_plaus(data["volume"], data["speed"]))
    data = data.assign(net_time_gap_below_max = data["net_time_gap"] < 60)
    data = data.assign(speed_occupancy_plausible = v_occ_plaus(data["speed"], data["occupancy"], qparams))   
return data

这些 .assign 中使用的三个函数也只是对所提供的两列的一些逻辑比较。 'qparams' 是一个 DataFrame,其中一行包含一些常量。每次调用这个 qualitycheck()-Function 时都会传入一个 5 行的数据框,然后会被这 14 列扩展并返回。使用 %timeit 我得到这个函数的 11.9ms 时间。问题是,我必须调用它大约 2500 万次,这将导致大约 83 小时。

那么有没有什么办法可以提高这个功能的性能呢?

编辑:这是三个函数:

def diffcheck(column):
    if column.sum() == 0:
        return True
    val0 = column.iloc[0]
    check = val0 == column
    if check.sum() < len(check):
        return True
    else:
        return False

def q_v_plaus(qs,vs):
    plaus = []
    for i in range(0,5):
        q = qs.iloc[i]
        v = vs.iloc[i]
        if q == 0 and v > 0:
            plaus.append(False)
        elif q > 0 and v == 0:
            plaus.append(False)
        else:
            plaus.append(True)
    return plaus

【问题讨论】:

  • 在我看来主要问题应该在你的函数diffcheckq_v_plausv_occ_plaus,你能把这个函数添加到问题中吗?

标签: python pandas performance assign


【解决方案1】:

主要问题是您为 5 行块调用此函数,更好的性能应该是 1k、10k 行块。

函数DataFrame.assign 有点慢,但主要问题应该在您的自定义函数中diffcheckq_v_plausv_occ_plaus - 我猜不是矢量化的(如果可能的话,如果没有看到它就不可能说)。

更快一点是删除assign并通过.values比较替换Series1d numpy array

def qualitycheck(data, qparams, qid):
    data['parameter_set'] = qid
    data['volume_below_max'] = data["volume"].values < int(qparams["max_volume"])
    ...
    ...    

我尝试优化你的功能:

def diffcheck(column):
    if column.values.sum() == 0:
        return True
    val0 = column.iat[0]
    check = val0 == column
    return check.values.sum() < len(check)

函数适用于所有行,而不仅仅是前 5 行:

def q_v_plaus1(qs,vs):
    qs = qs.values
    vs= vs.values
    m1 = (qs== 0) & (vs > 0)
    m2 = (qs> 0) & (vs == 0)
    return ~(m1 | m2)

被重写为更快的替代方案:

def q_v_plaus1(qs,vs):
    qs = qs.values
    vs= vs.values
    m1 = (qs!= 0) | (vs <= 0)
    m2 = (qs<= 0) | (vs != 0)
    return m1 & m2

【讨论】:

  • 添加功能,第三个和第二个差不多,只是逻辑有点不同。
  • @Morb - 我有点困惑,q_v_plaus 只调用前 5 行?不是所有行?
  • DataFrame 只有 5 行。在调用 qualitycheck 函数之前,原始 DataFrame 被划分为 5 行的块(这与 diffcheck 相关)
  • @Morb - 嗯,可以创建块 1000 吗?
  • 嗯,谢谢。我对其进行了更改,以便将整个数据帧传递给函数。现在每 5 行只调用一次diffcheck,但其余的分配一次完成所有 500,000 行。这样工作得更快。
猜你喜欢
  • 1970-01-01
  • 2020-09-15
  • 2018-11-25
  • 1970-01-01
  • 1970-01-01
  • 2021-12-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-07
相关资源
最近更新 更多