Вычислить лидеров конкурентоспособных гонщиков на протяжении всего сезона


У меня есть таблица в моей БД, которая содержит всадников в качестве строк и их очки на протяжении всего сезона, как колонны. Здесь представлены столбцы:

['name', 'wwq_id', 'wwq_code', 'year', 'round1_qualy', 'round1_final', 
'round1_timed', 'round1_total_qualy', 'round1_total_qualy_position', 
'round1_total_final', 'round1_total_final_position', 'round1_total_timed', 
'round1_total_timed_position', 'round1_total', 'round1_total_position'...etc

В 'round1_qualy', 'round1_final', 'round1_timed' все приехали из разных таблиц и добавляются с помощью другой функции. Как только они будут в БД все total столбцы вычисляются с помощью генерируемых столбцов в MySQL.

Мне нужно, чтобы вычислить положение всадника в разные моменты сезона. И. Е. После первого раунда qualy, после второго раунда финала, и т. д.

Вот код у меня есть сейчас:

def set_positions():
    """Add positions to the DB for each column in our overall table"""
    engine = sql.create_engine(MYSQL_CON_STRING)
    connection = engine.connect()
    trans = connection.begin()

    # Men, Women, Junior
    for category in CATEGORIES:
        table = category + '_overall'
        df = pd.read_sql('SELECT * FROM {0}'.format(table), engine)
        points_columns_list = [col for col in df.columns
                               if 'total' in col and 'position' not in col]

        # Calculate the rank based on current total points column and
        # insert into current column index + 1
        for points_column in points_columns_list:
            position_index = df.columns.get_loc(points_column) + 1
            position_column = df.columns[position_index]
            current_points = df.groupby('year')
            position = \
                current_points[points_column].rank(ascending=0,
                                                   method='min').astype(int)
            df.loc[:, position_column] = position.values

            # No points awarded in this and/or previous rounds. Everyone is 
            # at 0 so everyone is rank 1
            df.loc[(df[points_column] == 0)
                   & (df[position_column] == 1), position_column] = 'NULL'

            # Add rows to the DB
            for row in df.itertuples():
                connection.execute('UPDATE {0} '
                                   'SET {1} = {2} '
                                   'WHERE year = {3} and name = "{4}"'
                                   ''.format(table, position_column,
                                             getattr(row, position_column),
                                             getattr(row, 'year'),
                                             getattr(row, 'name')))
        trans.commit()
    connection.close()

Код прекрасно работает, он просто занимает много времени. Эта функция не очень часто выполняется, но учитывая насчитывается около 8000 строк в таблице, это займет немного времени.

Есть ли способ, чтобы получить сложность вниз?



122
3
задан 1 марта 2018 в 10:03 Источник Поделиться
Комментарии
1 ответ

Вы должны стремиться уменьшить количество запросов к вашей БД. Вместо того, чтобы обновить всю таблицу, строку за строкой, каждый раз, когда вы вычислить новое значение, вы могли бы:


  1. загрузка данных (используя pd.read_sql_table);

  2. выполнять вычисления позиции (это может потребоваться для использования None или pd.np.NaN вместо 'NULL');

  3. писать всю новую таблицу сразу по окончании (через df.to_sql).

Переписать может выглядеть так:

def set_positions():
"""Add positions to the DB for each column in our overall table"""
engine = sql.create_engine(MYSQL_CON_STRING)
connection = engine.connect()
trans = connection.begin()

# Men, Women, Junior
for category in CATEGORIES:
table = category + '_overall'
df = pd.read_sql_table(table, engine)
compute_positions_for_table(df)
df.to_sql(table, engine, if_exists='replace')
trans.commit()
connection.close()

def compute_positions_for_table(df):
points_columns_list = [col for col in df.columns
if 'total' in col and 'position' not in col]

# Calculate the rank based on current total points column and
# insert into current column index + 1
for points_column in points_columns_list:
position_index = df.columns.get_loc(points_column) + 1
position_column = df.columns[position_index]
current_points = df.groupby('year')
position = current_points[points_column].rank(ascending=0, method='min').astype(int)
df.loc[:, position_column] = position.values

# No points awarded in this and/or previous rounds. Everyone is
# at 0 so everyone is rank 1
df.loc[(df[points_column] == 0)
& (df[position_column] == 1), position_column] = None

И даже если вы не можете "заменить" таблице, вы все равно должны обновить таблицу только один раз в конце вычислений, а не на каждом новом вычислении столбца.

3
ответ дан 1 марта 2018 в 12:03 Источник Поделиться