Как ускорить назначение столбцов pd.Dataframe? - PullRequest
0 голосов
/ 03 декабря 2018

Итак, я пытаюсь добавить столбцы к существующему фрейму данных, используя в основном логические сравнения:

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

Три функции, используемые в этих именах, также являются лишь некоторыми логическими сравнениями двух предоставленных столбцов.'qparams' - это DataFrame с одной строкой с некоторыми константами.Каждый раз, когда эта функция qualitycheck () вызывается, передается фрейм данных с 5 строками, который затем расширяется на эти 14 столбцов и возвращается.С% timeit я получаю время 11,9 мс для этой функции.Проблема в том, что я должен назвать это около 25 миллионов раз, что приведет к примерно 83 ч.

Так есть ли способ улучшить производительность этой функции?

edit: вот три функции:

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

1 Ответ

0 голосов
/ 03 декабря 2018

Основная проблема заключается в том, что вы вызываете эту функцию для кусков 5 строк, лучшая производительность должна быть для кусков 1k, 10k строк.

Функция DataFrame.assign немного медленнее, но основная проблемадолжно быть в ваших пользовательских функциях diffcheck, q_v_plaus, v_occ_plaus - я думаю, не векторизовано (если это возможно, или нет, это невозможно, если вы не видите его).

Немного быстрее это удалить assign и сравните на .values для замены Series на 1d 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
...