Самый быстрый способ итерации и обновления фрейма данных

ПРОБЛЕМА: у меня есть фрейм данных, показывающий, какие задания выбрали ученики и какие оценки они за них получили. Я пытаюсь определить, какие подмножества заданий были выполнены большинством учащихся и общее количество баллов, заработанных за них. Метод, который я использую, очень медленный, поэтому мне интересно, какой самый быстрый способ.

Мои данные имеют такую ​​структуру:

СТУДЕНТ ЗАДАНИЕ1 ЗАДАНИЕ2 ЗАДАНИЕ3 ... ЗАДАНИЕ20 Студент1 50 75 100 ... 50 Студент2 75 25 NaN ... NaN ... Студент2000 100 50 NaN ... 50

ЦЕЛЕВОЙ ВЫХОД: Для каждой возможной комбинации заданий я пытаюсь получить количество выполненных заданий и сумму баллов, заработанных за каждое отдельное задание подмножеством учащихся, выполнивших именно эту комбинацию заданий:

ASSIGNMENT_COMBO NUMBER_OF_STUDENTS_WHO_DID_THIS_COMBO ЗАДАНИЕ1 ВСЕГО БАЛЛОВ ЗАДАНИЕ2 ВСЕГО БАЛЛОВ ЗАДАНИЕ3 ВСЕГО БАЛЛОВ ... ЗАДАНИЕ20 ВСЕГО БАЛЛОВ Задание 1, Задание 2 900 5000 400 NaN ... NaN Задание 1, Задание 2, Задание 3 100 3000 500 ... NaN Задание 2, Задание 3 750 NaN 7000 750 ... NaN ... Все возможные комбо, включая любое количество заданий

ЧТО Я ПРОБЫЛ: Во-первых, я использую itertools для создания комбинаций заданий, а затем перебираю фреймворк данных, чтобы классифицировать каждого ученика по тому, какие комбинации заданий они выполнили:

for combo in itertools.product(list_of_assignment_names, repeat=20):
for i, row in starting_data.iterrows():
    ifor = str(combo)
    ifor_val = 'no'
    for item in combo:
        if row[str(item)]>0:
             ifor_val = 'yes'
    starting_data.at[i,ifor] = ifor_val

Затем я создаю второй фрейм данных (assignmentcombostats), в котором каждая комбинация представлена ​​в виде строки для подсчета количества студентов, выполнивших каждую комбинацию:

numberofstudents =[]
for combo in assignmentcombostats['combo']:
    column = str(combo)
    number = len(starting_data[starting_data[column] == 'yes'])
    numberofstudents.append(number)
assignmentcombostats['numberofstudents'] = numberofstudents

Это работает, но очень медленно.

РЕСУРСЫ: я просмотрел несколько ресурсов -

  1. Этот пост - это то, на чем я основываю свой текущий метод
  2. На этой странице есть идеи для более быстрой итерации, но я не уверен, как лучше всего решить мою проблему с помощью векторизации

Вы пытались использовать какие-либо собственные функции панд? groupby и т.д.? Pandas по своей сути является столбчатым, поэтому итерация по его строкам очень медленная, а не так, как предполагается использовать pandas...

MatBailie 20.02.2023 01:27

Можете ли вы дать мне представление, как это будет работать здесь?

moe 20.02.2023 01:30
Потяните за рычаг выброса энергососущих проектов
Потяните за рычаг выброса энергососущих проектов
На этой неделе моя команда отменила проект, над которым я работал. Неделя усилий пошла насмарку.
Инструменты для веб-скрапинга с открытым исходным кодом: Python Developer Toolkit
Инструменты для веб-скрапинга с открытым исходным кодом: Python Developer Toolkit
Веб-скрейпинг, как мы все знаем, это дисциплина, которая развивается с течением времени. Появляются все более сложные средства борьбы с ботами, а...
Библиотека для работы с мороженым
Библиотека для работы с мороженым
Лично я попрощался с операторами print() в python. Без шуток.
Эмиссия счетов-фактур с помощью Telegram - Python RPA (BotCity)
Эмиссия счетов-фактур с помощью Telegram - Python RPA (BotCity)
Привет, люди RPA, это снова я и я несу подарки! В очередном моем приключении о том, как создавать ботов для облегчения рутины. Вот, думаю, стоит...
Пошаговое руководство по созданию собственного Slackbot: От установки до развертывания
Пошаговое руководство по созданию собственного Slackbot: От установки до развертывания
Шаг 1: Создание приложения Slack Чтобы создать Slackbot, вам необходимо создать приложение Slack. Войдите в свою учетную запись Slack и перейдите на...
Учебник по веб-скрапингу
Учебник по веб-скрапингу
Привет, ребята... В этот раз мы поговорим о веб-скрейпинге. Целью этого обсуждения будет узнать и понять, что такое веб-скрейпинг, а также узнать, как...
0
2
66
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я попробовал навести порядок Ответ Брайана

  • Составьте список всех возможных комбинаций
  • Повторите каждую комбинацию, чтобы найти общее количество и количество студентов.
  • Объедините результаты в фрейм данных

Настройка: (составляет набор данных из 20 000 учащихся и 10 заданий)

import itertools

import pandas as pd
import numpy as np

# Bigger random sample data
def make_data(rows, cols, nans, non_nans):
  df = pd.DataFrame()
  df["student"] = list(range(rows))
  for i in range(1,cols+1):
    a = np.random.randint(low=1-nans, high=non_nans, size=(rows)).clip(0).astype(float)
    a[ a <= 0 ] = np.nan
    df[f"a{i:02}"] = a
  return df

rows = 20000
cols = 10
df = make_data(rows, cols, 50, 50)


# dummy columns, makes aggregates easier
df["students"] = 1
df["combo"] = ""

Трансформация:

# create a list of all possible assignment combinations (ignore first and last two)
assignments = df.columns[1:-2].tolist()
combos = []
for r in range(1, len(assignments)+1):
    new_combos = list(itertools.combinations(assignments, r))
    combos += new_combos

# create a list to hold the results
results = list(range(len(combos)))

# ignore the student identifier column
df_source = df.iloc[:, 1:]

# iterate over the combinations and compute the results
for ix, combo in enumerate(combos):

  # filter the dataframe for students who have completed this combo
  df_filter = df.loc[ df[ list(combo) ].notnull().all(axis=1) ]

  # aggregate the results to a single row (sum of the dummy students column counts the rows)
  df_agg = df_filter.groupby("combo", as_index=False).sum().reset_index(drop=True)

  # store the assignment comination in the results
  df_agg["combo"] = ",".join(combo)

  # add the results to the list
  results[ix] = df_agg

# create a new dataframe from the results list
combo_stats_df = pd.concat(results).reset_index(drop = True)

В этой демонстрации требуется ~6 секунд, чтобы вернуть ~1000 строк результатов.

Для 20 заданий это ~1 000 000 строк результатов, то есть ~6000 секунд (более 1,5 часов).

Даже на моем рабочем столе обработка 1000 комбинаций занимает ~2 секунды, то есть ~0,5 часа на ~1 000 000 комбинаций из 20 заданий.

Сначала я пытался написать его без цикла, но процесс был остановлен из-за использования слишком большого объема памяти. Мне нравится головоломка, она помогает мне учиться, поэтому я подумаю, есть ли способ избежать петли, оставаясь в памяти.

Другие вопросы по теме