Агрегация данных Python (функция»Графы» в Excel)

#python #excel #data-analysis #aggregation #countif

Вопрос:

Давний пользователь Excel превратился здесь в нового пользователя Python. У меня есть следующий фрейм данных идентификаторов продуктов:

 productID              sales
6976849                194,518,557             
11197085               277,387,647
70689391               197,511,925
70827164               242,995,691
70942756               1,529,319,200
 

(В интерфейсе это выглядит не очень красиво, но в Python мне удалось поместить это в фрейм данных со столбцом для идентификатора и столбцом для продаж.)

Каждый идентификатор продукта содержит общее количество продаж.

Что мне нужно, так это подсчитать, сколько продуктов имеют более 200 000 000 продаж, а также сколько продуктов имеют менее 200 000 000 продаж.

Общее количество ведер Более 200 000 000 x Менее 200 000 000 лет

В Excel я бы сделал это с помощью функции быстрого подсчета, но я не уверен, как это работает в Python.

Мне на удивление трудно найти, как это сделать-может ли кто-нибудь указать мне правильное направление? Даже просто названия функций, чтобы я мог прочитать о них, были бы полезны!

Спасибо!!

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

1. Воспользуйся Pandas

2. Как новичок, я бы лично не рекомендовал использовать фреймы данных pandas, пока вы не познакомитесь с самим языком. Они довольно мощные, но ваше приложение довольно простое и не нуждается в их гибкости. Сохранение файла в формате csv, затем чтение файла и анализ текста будут хорошим упражнением в обучении работе с файлами, преобразованию строк и обработке простых структур данных (например, списков и т. Д.).

3. Ты прав, @Аарон. Можете ли вы ответить на вопрос с помощью csv модуля, пожалуйста?

Ответ №1:

Использовать Pandas и value_counts :

 import pandas as pd

df = pd.read_excel('data.xlsx')
over, under = df['sales'].gt(200000000).value_counts().tolist()
 

Выход:

 >>> over
3

>>> under
2
 

Шаг за шагом:

 # Display your data after load file
>>> df
   productID       sales
0    6976849   194518557
1   11197085   277387647
2   70689391   197511925
3   70827164   242995691
4   70942756  1529319200

# Select the column 'sales'
>>> df['sales']
0     194518557
1     277387647
2     197511925
3     242995691
4    1529319200
Name: sales, dtype: int64

# Sales are greater than 200000000? (IF part of COUNTIF)
>>> df['sales'].gt(200000000)
0    False
1     True
2    False
3     True
4     True
Name: sales, dtype: bool

# Count True (over) and False (under) (COUNT part of COUNTIF)
>>> df['sales'].gt(200000000).value_counts()
True     3
False    2
Name: sales, dtype: int64

# Convert to list
>>> df['sales'].gt(200000000).value_counts().tolist()
[3, 2]

# Set variables over / under
>>> over, under = df['sales'].gt(200000000).value_counts().tolist()
 

Обновить

Я должен также добавить, что в наборе данных 100 миллионов строк, и мне понадобится больше сегментов, что-то вроде Более 500 миллионов между 200 миллионами и 500 миллионами между 100 миллионами и 200 миллионами менее 100 миллионов. Можете ли вы сказать мне, как я буду устанавливать сегменты?

Использовать pd.cut и value_counts :

 df['buckets'] = pd.cut(df['sales'], right=False, ordered=True,
                       bins=[0, 100e6, 200e6, 500e6, np.inf],
                       labels=['under 100M', '100-200M',
                               '200-500M', 'over 500M'])
 
 >>> df
   productID       sales    buckets
0    6976849   194518557   100-200M
1   11197085   277387647   200-500M
2   70689391   197511925   100-200M
3   70827164   242995691   200-500M
4   70942756  1529319200  over 500M

>>> df.value_counts('buckets', sort=False)
buckets
under 100M    0
100-200M      2
200-500M      2
over 500M     1
dtype: int64
 

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

1. Спасибо! Я также должен добавить, что в наборе данных 100 миллионов строк, и мне понадобится больше блоков, что-то около 500 миллионов между 200 миллионами и 500 миллионами между 100 миллионами и 200 миллионами менее 100 миллионов. Можете ли вы сказать мне, как я буду устанавливать блоки?

2. Я обновил свой ответ в соответствии с вашим комментарием. Не забудьте принять ответ , если он соответствует вашим потребностям. Это важно для всех нас.

Ответ №2:

Существует множество очень мощных библиотек, которые помогут вам быстро выполнять задачи, но вы упомянули, что только начинаете, поэтому я бы рекомендовал придерживаться только самого python в качестве учебного опыта.

Excel может сохранять файлы в формате «CSV», который представляет собой очень простой текстовый формат файла. CSV-файлы, как правило, представляют собой просто построчное представление каждой строки в вашей электронной таблице, со столбцами, разделенными запятыми. Очень простым решением вашего вопроса может быть чтение такого файла строка за строкой, определение того, больше или меньше количество продаж, чем заданное число, и добавление одного в соответствующую группу.

Начать с чтения файла довольно просто. Чтение файлов в коде немного отличается от того, к чему вы привыкли, но это очень просто и почти всегда одинаково для разных языков программирования. Сначала вы» открываете » файл, который в основном запрашивает доступ операционной системы. ОС определит, должен ли у вас быть доступ или нет, и если да, предоставит вам доступ к тому, что составляет курсор, который может сканировать файл. Этот «курсор» часто называют «дескриптором файла» или в python просто «файловым объектом».

 file_obj = open("data.csv", "r")  #"r" for reading mode (instead of write)
 

Как только у нас будет дескриптор, мы сможем вызвать его read метод для чтения части или всего файла. Передача числа покажет, сколько символов (новая строка и некоторые другие невидимые коды считаются символом) для чтения, или в python вы не можете передавать параметры, и он прочитает весь файл. Поскольку мы открыли файл в текстовом режиме (по умолчанию), мы получим обычную строку.

 file_contents = file_obj.read()
 

Теперь, когда мы скопировали содержимое файла в строку, мы можем закрыть файл и сообщить операционной системе, что мы закончили с ним.

 file_obj.close()
 

Вы часто можете видеть это немного по-другому в python, используя with контекст, чтобы немного очистить код и убедиться, что файл всегда закрывается:

 with open("data.csv", "r") as file_obj:
    file_contents = file_obj.read()
 

Теперь у вас есть большая длинная строка, содержащая весь CSV-файл. Мы хотим иметь возможность переходить строка за строкой, поэтому нам приходится разделять строку на части в любом месте, где мы находим символ новой строки. Строки Python имеют удобный способ сделать это с помощью str.split метода:

 file_lines = file_contents.split("n") #split the string into a list of strings by splitting on n chars
 

Теперь с помощью этого списка мы создадим цикл для чтения каждой строки и определим, было ли у продукта более или менее 200 000 000 продаж. Для этого нам нужно будет найти соответствующий раздел каждой строки, преобразовать его в число и с помощью if оператора решить, что с ним делать. Простейшая форма цикла python состоит в том, чтобы просмотреть каждый элемент в простом списке элементов: for line in file_lines: . Теперь на каждой итерации внутри цикла, line переменная будет заполнена тем, что было в этой строке файла. Пока в csv — файле нет пустых строк и заголовков, нам в значительной степени нужно только найти второе значение (разделенное запятой) и преобразовать его в число. Здесь мы снова воспользуемся этим str.split методом, чтобы разделить строку на запятую и преобразовать второй элемент в целое число (помните, что python использует индексацию на основе 0, поэтому 2-й элемент будет иметь индекс 1). Отсюда мы можем добавить некоторую логику, чтобы определить, следует ли нам считать один меньше или больше 200 миллионов.

 over = 0
under = 0
for line in file_lines:
    line_items = line.split(",")
    sales = int(line_items[1])
    if sales > 200000000:
        over = over   1
    else:
        under = under   1
 

Наконец, вот более продвинутая версия после прочтения вашего комментария о необходимости большего количества «ведер».

 buckets = [0] * 8 #list of 8 buckets each starting at 0
bucket_edges = [0, 1e6, 2e6, 5e6, 1e7, 2e7, 5e7, 1e8, 2e8] #an even more advanced version would find the max and min of the sales figures, and dynamically calculate the bucket edges
with open("data.csv") as f: #"r" mode is actually the default
    sales = [] #an empty list
    for line in f: #a default behavior of file handles is to read line-by-line in for loops
        line = line.strip() #remove leading and trailing whitespace
        if not line: #an empty string will act like "False"
            continue #advance to the next loop iteration
        sales.append(int(line.split(",")[1])) #combine a few operations in a single line, and build up a list of sales figures
for sale in sales:
    for i in range(len(buckets)):
        if bucket_edges[i] <= sale < bucket_edges[i 1]:
            buckets[i]  = 1
for i in range(len(buckets)):
    print(bucket_edges[i], "to", bucket_edges[i 1], ":", buckets[i])
 

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

1. Хорошее объяснение, за это 1. Но вы должны использовать csv модуль (это модуль стандартной библиотеки). Вероятно, вы также можете использовать bisect модули (bisect_left) и collections (defaultdict). Если вы не используете какие-либо модули из стандартной библиотеки, Python будет не так полезен.

Ответ №3:

Если вы используете convtools файл xlsx и его преобразование в csv, то короткий ответ таков:

 # pip install convtools
from convtools import conversion as c

converter = c.aggregate({
    "below_200": c.ReduceFuncs.Count(where=c.item("sales") < 200000000),
    "above_200": c.ReduceFuncs.Count(where=c.item("sales") >= 200000000),
}).gen_converter()
results = converter(list_of_dicts)
 

Более длинный:

 import csv

# pip install convtools
from convtools import conversion as c

buckets = [
    (None, 200000000),
    (200000000, 220000000),
    (220000000, 240000000),
    (220000000, None),
]


def bucket_to_condition(bucket, input_):
    conditions = []
    left, right = bucket
    if left is not None:
        conditions.append(input_ >= left)
    if right is not None:
        conditions.append(input_ < right)
    if not conditions:
        return {}
    return {
        "where": c.and_(*conditions) if len(conditions) > 1 else conditions[0]
    }


with open("input_data.csv", "w") as f:
    reader = csv.reader(f)

    # skip header (assuming it's known)
    next(header)

    converter = (
        c.iter(
            {
                "productID": c.item(0),
                "sales": c.item(1).as_type(int),
            }
        )
        .pipe(
            c.aggregate(
                {
                    f"{bucket}": c.ReduceFuncs.Count(
                        **bucket_to_condition(bucket, c.item("sales")),
                    )
                    for bucket in buckets
                }
            )
        )
        .gen_converter()
    )
    results = converter(reader)