Агрегация Python без PANDAS - PullRequest
1 голос
/ 21 марта 2019

У меня есть отсортированный и вложенный список.Каждый элемент в списке имеет 3 подэлемента;Drugname, Doctor_id, Сумма.Для данного drugname (которое повторяется) идентификаторы доктора разные, как и суммы.См. Примерный список ниже.

Мне нужен вывод, в котором для каждого имени друга мне нужно подсчитать общие УНИКАЛЬНЫЕ идентификаторы доктора и сумму в долларах для этого лекарства.Например, для приведенного ниже фрагмента списка.

[
   ['CIPROFLOXACIN HCL', 1801093968, 61.49],
   ['CIPROFLOXACIN HCL', 1588763981, 445.23],
   ['HYDROCODONE-ACETAMINOPHEN', 1801093968, 251.52],
   ['HYDROCODONE-ACETAMINOPHEN', 1588763981, 263.16],
   ['HYDROXYZINE HCL', 1952310666, 945.5],
   ['IBUPROFEN', 1801093968, 67.06],
   ['INVEGA SUSTENNA', 1952310666, 75345.68]
]

Требуемый вывод такой, как показано ниже.

[
   ['CIPROFLOXACIN HCL', 2, 516.72],
   ['HYDROCODONE-ACETAMINOPHEN', 2, 514.68]
   ['HYDROXYZINE HCL', 1, 945.5]
   ['IBUPROFEN', 1, 67.06]
   ['INVEGA SUSTENNA', 1, 75345.68]
]

В мире баз данных это проще всего с простой GROUP BY ondrugname.В Python мне не разрешено использовать PANDAS, NumPy и т. Д. Только основные строительные блоки Python.Я попробовал приведенный ниже код, но не могу сбросить переменную count для подсчета идентификаторов врачей и сумм.Этот закомментированный код является одной из нескольких попыток.Не уверен, что мне нужно использовать вложенный цикл for или цикл for-while.

Вся помощь приветствуется!

aggr_list = []
temp_drug_name = ''
doc_count = 0
amount = 0
for list_element in sorted_new_list:
    temp_drug_name = list_element[0]
    if temp_drug_name == list_element[0]:
        amount += float(amount)
        doc_count += 1

    aggr_list.append([temp_drug_name, doc_count, amount])

print(aggr_list)

Ответы [ 2 ]

0 голосов
/ 21 марта 2019

Вот решение с упором на удобочитаемость, оно не учитывает, что записи в вашем исходном списке отсортированы по названию препарата.

Он проходит один раз для всех записей ваших данных, затемпропуск числа уникальных лекарств.

Чтобы сделать только один проход для всех записей ваших отсортированных данных, см. @blhsing solution

from collections import defaultdict, namedtuple
Entry = namedtuple('Entry',['doctors', 'prices'])
processed_data = defaultdict(lambda: Entry(doctors=set(), prices=[]))

for entry in data:
    drug_name, doctor_id, price = entry
    processed_data[drug_name].doctors.add(doctor_id)
    processed_data[drug_name].prices.append(price)

stat_list = [[drug_name, len(entry.doctors), sum(entry.prices)] for drug_name, entry in processed_data.items()]
0 голосов
/ 21 марта 2019

Поскольку список уже отсортирован, вы можете просто перебрать список (с именем l в приведенном ниже примере) и отслеживать имя последней итерации, и если имя текущей итерации отличается от последнейвставьте новую запись в вывод.Используйте набор для отслеживания идентификаторов врачей, уже замеченных для текущего препарата, и увеличивайте только второй элемент последней записи в выходных данных на 1, если идентификатор доктора не виден.И увеличиваем третий элемент последней записи вывода на величину текущей итерации:

output = []
last = None
for name, id, amount in l:
    if name != last:
        output.append([name, 0, 0])
        last = name
        ids = set()
    if id not in ids:
        output[-1][1] += 1
        ids.add(id)
    output[-1][2] += amount

output становится:

[['CIPROFLOXACIN HCL', 2, 506.72],
 ['HYDROCODONE-ACETAMINOPHEN', 2, 514.6800000000001],
 ['HYDROXYZINE HCL', 1, 945.5],
 ['IBUPROFEN', 1, 67.06],
 ['INVEGA SUSTENNA', 1, 75345.68]]

Обратите внимание, что десятичные числа с плавающей запятой являются приблизительнымив двоичной системе, которую использует компьютер (пожалуйста, прочитайте Математика с плавающей запятой не работает? ), поэтому некоторые незначительные ошибки неизбежны, как видно из суммы второй записи выше.

...