Я пытаюсь понять, как создать эквивалент СУММЕСЛИ в 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
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()
condition_types['sum_of_sales'] = condition_types.apply(lambda row: sumif (row, value_column = "sum_of_sales"), axis=1)
Надеюсь, это достаточно понятно и пример не слишком сложен.
@Dinks123 Dinks123 В ответе используется тот же подход, что и я. Это слишком медленно
Используйте np.where для части IF, затем np.sum, это должно быть достаточно быстро.
Для более общего подхода вы можете melt
sales_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! Это работает как абсолютный шарм :-)
Я бы предложил переосмыслить ваш подход, и это основано на условиях, которыми вы поделились. Если я понимаю вопрос, изложенный выше, вы сопоставляете записи в столбце 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
На этот вопрос есть ответ, который может быть подходящим: stackoverflow.com/questions/65235226/…