Замена для dataframe.iterrows () - PullRequest
       4

Замена для dataframe.iterrows ()

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

Я работаю над сценарием для переноса данных из MongoDB в Clickhouse.Из-за того, что вложенные структуры не реализованы достаточно хорошо в Clickhouse, я перебираю вложенные структуры и приводю их к плоскому представлению, где каждый элемент вложенной структуры представляет собой отдельную строку в базе данных Clickhouse.

Я перебираю список словарей и принимаю целевые значения.Структура выглядит следующим образом:

[
 {
  'Comment': None,
  'Details': None,
  'FunnelId': 'MegafonCompany',
  'IsHot': False,
  'IsReadonly': False,
  'Name': 'Новый',
  'SetAt': datetime.datetime(2018, 4, 20, 10, 39, 55, 475000),
  'SetById': 'ekaterina.karpenko',
  'SetByName': 'Екатерина Карпенко',
  'Stage': {
            'Label': 'Новые',
            'Order': 0,
            '_id': 'newStage'
           },
  'Tags': None,
  'Type': 'Unknown',
  'Weight': 120,
  '_id': 'new'
 },
 {
  'Comment': None,
  'Details': {
              'Name': 'взят в работу', 
              '_id': 1
             },
  'FunnelId': 'MegafonCompany',
  'IsHot': False,
  'IsReadonly': False,
  'Name': 'В работе',
  'SetAt': datetime.datetime(2018, 4, 20, 10, 40, 4, 841000),
  'SetById': 'ekaterina.karpenko',
  'SetByName': 'Екатерина Карпенко',
  'Stage': {
            'Label': 'Приглашение на интервью',
            'Order': 1,
            '_id': 'recruiterStage'
           },
  'Tags': None,
  'Type': 'InProgress',
  'Weight': 80,
  '_id': 'phoneInterview'
 }
]

У меня есть функция, которая делает это на объекте dataframe с помощью метода data.iterrows ():

def to_flat(data, coldict, field_last_upd):

m_status_history = stc.special_mongo_names['status_history_cand']
n_statuse_change = coldict['n_statuse_change']['name']

data[n_statuse_change] = n_status_change(dp.force_take_series(data, m_status_history))
flat_cols = [ x for x in coldict.values() if x['coltype'] == stc.COLTYPE_FLAT ]
old_cols_names = [ x['name'] for x in coldict.values() if x['coltype'] == stc.COLTYPE_PREPARATION ]
t_time = time.time()
t_len = 0
new_rows = list()

    for j in range(row[n_statuse_change]):
        t_new_value_row = np.empty(shape=[0, 0])
        for k in range(len(flat_cols)):
            if flat_cols[k]['colsubtype'] == stc.COLSUBTYPE_FLATPATH:
                new_value = dp.under_value_line(
                    row,
                    path_for_status(j, row[n_statuse_change]-1, flat_cols[k]['path'])
                )
                # Дополнительно обрабатываем дату
                if flat_cols[k]['name'] == coldict['status_set_at']['name']:
                    new_value = dp.iso_date_to_datetime(new_value)

                if flat_cols[k]['name'] == coldict['status_set_at_mil']['name']:
                    new_value = dp.iso_date_to_miliseconds(new_value)

                if flat_cols[k]['name'] == coldict['status_stage_order']['name']:
                    try:
                        new_value = int(new_value)
                    except:
                        new_value = new_value
            else:
                if flat_cols[k]['name'] == coldict['status_index']['name']:
                    new_value = j

            t_new_value_row = np.append(t_new_value_row, dp.some_to_null(new_value))
        new_rows.append(np.append(row[old_cols_names].values, t_new_value_row))
pdb.set_trace()
res = pd.DataFrame(new_rows, columns = [
    x['name'] for x in coldict.values() if x['coltype'] == stc.COLTYPE_FLAT or x['coltype'] == stc.COLTYPE_PREPARATION
])

return res

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

Я заметил, что если вложенная структура достаточно велика, она начинает работать намного медленнее,Я нашел статью, в которой сравниваются разные методы итерации в Python. article

Утверждается, что итерация по методу .apply () намного быстрее, а векторизация - еще быстрее.Но приведенные примеры довольно тривиальны и используют одну и ту же функцию для всех значений.Можно ли выполнять итерации по объектам панд быстрее, используя различные функции для разных типов данных?

1 Ответ

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

Я думаю, что вашим первым шагом должно быть преобразование ваших данных в фрейм данных pandas, тогда с ним будет намного легче справиться.Я не мог описать те функции, которые вы хотели запустить, но, возможно, мой пример помогает

import datetime
import pandas as pd

data_dict_array = [
 {
  'Comment': None,
  'Details': None,
  'FunnelId': 'MegafonCompany',
  'IsHot': False,
  'IsReadonly': False,
  'Name': 'Новый',
  'SetAt': datetime.datetime(2018, 4, 20, 10, 39, 55, 475000),
  'SetById': 'ekaterina.karpenko',
  'SetByName': 'Екатерина Карпенко',
  'Stage': {
            'Label': 'Новые',
            'Order': 0,
            '_id': 'newStage'
           },
  'Tags': None,
  'Type': 'Unknown',
  'Weight': 120,
  '_id': 'new'
 },
 {
  'Comment': None,
  'Details': {
              'Name': 'взят в работу', 
              '_id': 1
             },
  'FunnelId': 'MegafonCompany',
  'IsHot': False,
  'IsReadonly': False,
  'Name': 'В работе',
  'SetAt': datetime.datetime(2018, 4, 20, 10, 40, 4, 841000),
  'SetById': 'ekaterina.karpenko',
  'SetByName': 'Екатерина Карпенко',
  'Stage': {
            'Label': 'Приглашение на интервью',
            'Order': 1,
            '_id': 'recruiterStage'
           },
  'Tags': None,
  'Type': 'InProgress',
  'Weight': 80,
  '_id': 'phoneInterview'
 }
]

#converting your data into something pandas can read
# in particular, flattening the stage dict
for data_dict in data_dict_array:
    d_temp = data_dict.pop("Stage")
    data_dict["Stage_Label"] = d_temp["Label"]
    data_dict["Stage_Order"] = d_temp["Order"]
    data_dict["Stage_id"] = d_temp["_id"]

df = pd.DataFrame(data_dict_array)

# lets say i want to set comment to "cool" if name is 'В работе'
# in .loc[], the first argument is filtering the rows, the second argument is picking the column
df.loc[df['Name'] == 'В работе','Comment'] = "cool"
df
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...