Эффективный эквивалент SUMIF в Excel в Python

Я пытаюсь понять, как создать эквивалент СУММЕСЛИ в Python. Решение, которое у меня есть в настоящее время, работает, но оно слишком неэффективно, и его запуск занимает 20 минут.

Каким будет наиболее эффективный способ достичь желаемого результата?

Вот то, что я делаю сейчас, сведено к очень простой форме. В «настоящем» коде условий гораздо больше.

**sales_data customer_1**
Transactions   | Product Dimension 4 | Product Dimension 2 | Product Dimension 3 | sum_of_sales
-------------- | ------------------- | ------------------- | --------------------| -------------
1              | 50                  | F80                 | ETQ546              | 80
2              | 50                  | F80                 | SAS978              | 20
3              | 50                  | C36                 | JBH148              | 10
4              | 50                  | F80                 | ETQ546              | 80
5              | 50                  | F80                 | SAS978              | 20
6              | 50                  | C36                 | JBH148              | 10
7              | 20                  | A20                 | OPW269              | 15
8              | 20                  | A20                 | DUW987              | 65
9              | 20                  | v90                 | OWQ897              | 47



**condition_types BEFORE ADDING SUMIF TO TABLE**
Transactions   | Type                | Product Dimensions  |
-------------- | ------------------- | ------------------- | 
customer_1     | ABC                 | 50                  | 
customer_1     | DEF                 | F80                 |
customer_1     | GHI                 | JBH148              | 


**condition_types AFTER ADDING SUMIF TO TABLE**
Transactions   | Type                | Product Dimensions  | sum_of_sales
-------------- | ------------------- | ------------------- | -------------
customer_1     | ABC                 | 50                  | 220
customer_1     | DEF                 | F80                 | 200
customer_1     | GHI                 | JBH148              | 20

Определить функцию sumif

def sumif (row, value_column):
    if row['Type'] == "ABC":
        filtered_data = sales_data.loc[
            (sales_data['Product_dimension_4'] == row['Product Dimensions'])
        ]
    elif row['Type'] == "DEF" and row['Product Dimensions'] in sales_data['Product_dimension_2'].unique():
        filtered_data = sales_data.loc[
            (sales_data['Product_dimension_2'] == row['Product Dimensions'])
        ]

    elif row['Type'] == "GHI" and row['Product Dimensions'] in sales_data['Product_dimension_3'].unique():
        filtered_data = sales_data.loc[
            (sales_data['Product_dimension_3'] == row['Product Dimensions'])
        ]

    else:
        return 0  # Return 0 instead of an empty string for consistency
    
    return filtered_data[value_column].sum()

Примените функцию sumif, используя loc

condition_types['sum_of_sales'] = condition_types.apply(lambda row: sumif (row, value_column = "sum_of_sales"), axis=1)

Надеюсь, это достаточно понятно и пример не слишком сложен.

На этот вопрос есть ответ, который может быть подходящим: stackoverflow.com/questions/65235226/…

Dinks123 07.08.2024 13:14

@Dinks123 Dinks123 В ответе используется тот же подход, что и я. Это слишком медленно

nicgl 07.08.2024 13:18

Используйте np.where для части IF, затем np.sum, это должно быть достаточно быстро.

Ketil Tveiten 07.08.2024 13:19
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
3
50
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

Для более общего подхода вы можете meltsales_data получить связь между 'Product Dimensions' и 'sum_of_sales', затем groupby на 'Product Dimensions', агрегировать с sum и объединить его с conditions_data:

sales_data = (
    pd.melt(
        sales_data,
        id_vars=["sum_of_sales"],
        value_vars=sales_data.filter(like = "Product Dimension").columns,
        value_name = "Product Dimensions",
    )
    .groupby("Product Dimensions", as_index=False)["sum_of_sales"]
    .sum()
)

condition_types = condition_types.merge(sales_data, how = "left")
  Transactions Type Product Dimensions  sum_of_sales
0   customer_1  ABC                 50           220
1   customer_1  DEF                F80           200
2   customer_1  GHI             JBH148            20

Но если каждый 'Type' должен соблюдать связь с определенным столбцом 'Product Dimension', вы можете создать сопоставление, а также использовать 'Type' для группировки и объединения:

m = {
    "Product Dimension 4": "ABC",
    "Product Dimension 2": "DEF",
    "Product Dimension 3": "GHI",
}

sales_data = pd.melt(
    sales_data,
    id_vars=["Transactions", "sum_of_sales"],
    value_vars=sales_data.filter(like = "Product Dimension").columns,
    var_name = "Product Dimension Type",
    value_name = "Product Dimensions",
)

sales_data["Type"] = sales_data["Product Dimension Type"].map(m)

sales_data = sales_data.groupby(["Product Dimensions", "Type"], as_index=False)[
    "sum_of_sales"
].sum()

condition_types = condition_types.merge(
    sales_data, on=["Product Dimensions", "Type"], how = "left"
)

Вывод для предоставленных данных одинаков, но может отличаться, если у вас есть повторяющиеся значения в разных столбцах 'Product Dimension'.

Спасибо, e-motta! Это работает как абсолютный шарм :-)

nicgl 07.08.2024 15:34

Я бы предложил переосмыслить ваш подход, и это основано на условиях, которыми вы поделились. Если я понимаю вопрос, изложенный выше, вы сопоставляете записи в столбце Type с конкретными столбцами в DataFrame sales_data - по сути, «ABC» сопоставляется с «Product_Dimension_4», «DEF» сопоставляется с «Product_Dimension_2», а «GHI» сопоставляется с «Product_Dimension_3». '. Если мое предположение верно, то приведенное ниже решение должно предложить более быстрый и эффективный маршрут с использованием функций Pandas:


df = {'Transactions':range(1,10), 
    'Product_Dimension_4': [50,50,50,50,50,50,20,20,20], 
    'Product_Dimension_2':['F80','F80','C36','F80','F80','C36','A20','A20','v90'], 
    'Product_Dimension_3':['ETQ546','SAS978','JBH148','ETq546','SAS978','JBH148','OPW269','DUW987','OWQ897'],
    'sum_of_sales':[80,20,10,80,20,10,15,65,47]}
df = pd.DataFrame(df)

cond = {'Transactions':['customer_1','customer_1','customer_1'], 
        'Type':['ABC','DEF','GHI'],
        'Product Dimensions':[50,'F80','JBH148']}
cond = pd.DataFrame(cond)

condition=(df
           .filter(like='Product')
           .isin(cond['Product Dimensions'].array)
           .astype(np.int8)
           .rename(columns = {'Product_Dimension_4':'ABC', 
                            'Product_Dimension_2':'DEF',
                            'Product_Dimension_3':'GHI'})
           .mask(lambda df: df.eq(1), 
                 df.sum_of_sales,
                 axis=0)
            .sum()
           )
cond.assign(sum_of_sales=cond.Type.map(condition))
  Transactions Type Product Dimensions  sum_of_sales
0   customer_1  ABC                 50           220
1   customer_1  DEF                F80           200
2   customer_1  GHI             JBH148            20

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