Агрегированное количество на основе строки и дополнительного столбца с использованием pandas

#python #pandas

#python #pandas

Вопрос:

У меня есть набор данных, который содержит данные, которые выглядят следующим образом:

 Month, Year, Quantity Sold, Product Name
11, 2017, 13, "Creatine Powder Supplement - 500g"
11, 2017, 10, "Gummies 1 bag"
11, 2017, 12, "Creatine Powder Supplement - 1000g"
11, 2017, 15, "Creatine Powder Supplement - 1500g"
11, 2017, 11, "Glucosamine - 500g"
11, 2017, 23, "Glucosamine - 1500g"
12, 2017, 17, "Creatine Powder Supplement - 1000g"
12, 2017, 24, "Glucosamine - 500g"
12, 2017, 13, "Glucosamine - 1500g"
1, 2018, 16, "Creatine Powder Supplement - 500g"
1, 2018, 13, "Creatine Powder Supplement - 1000g"
1, 2018, 10, "Gummies 1 bag"
1, 2018, 11, "Glucosamine - 500g"
1, 2018, 21, "Glucosamine - 1500g"
  

Я хочу рассчитать общий вес проданных товаров, разделенных месяцем и годом, для чего потребуется извлечь вес продукта из столбца «Название продукта», умножив его на столбец «Проданное количество», а затем предоставить общую сумму для соответствующего продукта.

Желаемый результат (я рассчитал только общий вес, проданный для первой строки):

 Matched data set:

Month, Year, Product Name, Total Weight Sold
11, 2017, Creatine Powder Supplement, 41000
11, 2017, Glucosamine, <total>
12, 2017, Creatine Powder Supplement, <total>
12, 2017, Glucosamine, <total>
1, 2018, Creatine Powder Supplement, <total>
1, 2018, Glucosamine, <total>
  

В дополнение к этому, для любых продуктов, которые не заканчиваются шаблоном - <number>g , я хочу вывести их в отдельный набор данных, чтобы их можно было просмотреть.

 UNmatched data set:

Month, Year, Quantity Sold, Product Name
11, 2017, 10, "Gummies 1 bag"
1, 2018, 10, "Gummies 1 bag"
  

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

Спасибо

Ответ №1:

Самое простое решение, о котором я могу думать, это

 product_data = df['Product Name'].str.extract('(?P<name>w ) - (?P<weight>d )g')
invalid_rows = df[product_data['weight'].isnull()]
product_data.drop(labels=invalid_rows.index, inplace=True)
df.drop(labels=invalid_rows.index, inplace=True)
df['Product Name'] = product_data['name']
df['Total'] = product_data['weight'].astype(np.int32) * df['Quantity Sold']
print(df.groupby(['Month', 'Year', 'Product Name']).sum()['Total'].reset_index())
print()
print(invalid_rows)
  

Какие результаты

   Month  Year Product Name  Total
0     1  2018     Creatine  21000
1     1  2018  Glucosamine  37000
2    11  2017     Creatine  41000
3    11  2017  Glucosamine  40000
4    12  2017     Creatine  17000
5    12  2017  Glucosamine  31500

   Month  Year Quantity Sold     Product Name
1     11  2017            10  "Gummies 1 bag"
11     1  2018            10  "Gummies 1 bag"
  

Комментарии:

1. Я думаю, что здесь отсутствует вторая часть, чтобы выводить все, что не совпадает отдельно, но это отвечает на первое. Я собираюсь обновить пример набора данных в вопросе, чтобы включить несоответствующие данные.

2. Так близко! Я не упомянул, что название продукта часто состоит из нескольких слов. Я отредактировал, чтобы отразить. Предоставленное регулярное выражение этого не фиксирует.

Ответ №2:

Вот решение на Python. Он записывает строки с ошибками в выходной файл и записывает исправные строки в терминал.

 from collections import defaultdict
import re

d = defaultdict(int)

with open('f0.txt', 'r') as f, open('err.txt', 'w') as fout:
    fout.write(f.readline()) # print header to err.txt

    for row in f:
        row = row.rstrip()
        if re.search(r'- d g"', row):
            month, yr, qty, product = row.split(', ')
            product = product.replace('g', '').replace('"', '')
            name, grams = product.split(' - ')
            key = ','.join([month, yr, name])
            d[key]  = int(qty) * int(grams)
        else:
            # handle this row (that doesn't have a Product and weight)
            fout.write(row   'n')

print(','.join(['Month', 'Year', 'Product Name', 'Total Sold']))

for key, total in d.items():
    print(f'{key},{total}')
  

Выводит на терминал:

 Month,Year,Product Name,Total Sold
11,2017,Creatine,41000
11,2017,Glucosamine,40000
12,2017,Creatine,17000
12,2017,Glucosamine,31500
1,2018,Creatine,21000
1,2018,Glucosamine,37000
  

Выводит в err.txt:

 Month, Year, Quantity Sold, Product Name
11, 2017, 10, "Gummies 1 bag"
1, 2018, 10, "Gummies 1 bag"