У меня есть фрейм данных, который показывает группу, подгруппу, предварительные и пост-цифры для каждого продукта.
Я хочу рассчитать процентное изменение для каждого продукта (как показано в столбцах 5 и 8). Однако у меня есть до 10 различных продуктов, для которых мне нужно рассчитать это. Я пытаюсь написать цикл for, чтобы сделать это для меня, но мне не повезло.
def myfunc(a, b):
return b/a-1
res = [myfunc(a, b) for a, b in zip(a, b)]
for a in [pre_product_A,pre_product_B]:
for b in [post_product_A,post_product_B]:
myfunc(a, b)
res
Единственный способ получить желаемый результат — создать новые столбцы по отдельности, но это повторяется.
df['product_A'] = (df.post_product_A/df.pre_product_A -1).round(2)
df['product_B'] = (df.post_product_B/df.pre_product_B -1).round(2)
df.head()
Если все ваши столбцы имеют одинаковые имена: pre_product_<product_name>
и post_product_<product_name>
, то вы можете создать новые столбцы для каждого из них в цикле следующим образом:
products = ["A", "B"] # list all your product names here
for product in products:
pre = df[f"pre_product_{product}"]
post = df[f"post_product_{product}"]
df[f"product_{product}"] = (post/pre -1).round(2)
В противном случае вам придется «жестко закодировать» имена столбцов:
pre_columns = ["pre_product_A", "pre_product_B"]
post_columns = ["post_product_A", "post_product_B"]
end_columns = ["product_A_Change", "product_B_Change"]
for pre, post, end in zip(pre_columns, post_columns, end_columns):
df[end] = (df[post]/df[pre] -1).round(2)
Что ты имеешь в виду? я не уверен, что понимаю
В моем списке есть продукт A, продукт B и т. д. вплоть до продукта F, например. Но когда я запускаю свой скрипт, он показывает результаты только для продукта F, а не для всех продуктов в моем списке.
Вот моя попытка:
#First make a sample df
import pandas as pd
data = [[15, 10, 10, 12], [12, 15, 2 , 6], [14, 10, 5, 10]]
df = pd.DataFrame(data, columns=['post_product_A',
'pre_product_A','post_product_B','pre_product_B'])
#Then Run
prodlist=['product_A','product_B']
for product in prodlist:
df['Change_'+product]=(100* (df['post_'+product] / df['pre_'+product] -1)).map("{:,.0f}%".format)
df
Это дало мне именно то, что я хотел, с небольшими корректировками. Поскольку у меня уже был фрейм данных, на который я хотел сослаться, я просто заменил часть «данные» своим фактическим фреймом данных. Я также хотел сохранить свои первые два столбца «Группа» и «Подгруппа», поэтому я добавил эти два столбца в свой список столбцов. Спасибо!!
Хорошо, но ваш запрос не совсем ясен...
Вы используете списки Python или фреймы данных?
У вас есть 10 разных товаров или групп?
Вот 3 простых фрагмента, которые могут вам помочь, надеясь понять, чего вы действительно хотите достичь.
Первое решение:
import pandas as pd
data = {
'Group': ['Group A', 'Group A', 'Group B', 'Group B'],
'Subgroup': ['Sub A', 'Sub B', 'Sub A', 'Sub B'],
'Pre-Product-1': [900, 50, 60, 40],
'Post-Product-1': [150, 70, 20, 10],
'Product-1-Change': ['50%', '50%', '-67%', '-75%'],
'Pre-Product-2': [200, 50, 60, 40],
'Post-Product-2': [150, 70, 10, 10],
'Product-2-Change': ['50%', '50%', '-67%', '-75%']
}
df = pd.DataFrame(data)
def calc_pct_change(pre, post):
return (post - pre) / pre * 100
for i, row in df.iterrows():
'''Define a function to calculate percentage change + use the % notation'''
for j in range(1, 3):
pre_col = f'Pre-Product-{j}'
post_col = f'Post-Product-{j}'
change_col = f'Product-{j}-Change'
pre = row[pre_col]
post = row[post_col]
change = calc_pct_change(pre, post)
df.loc[i, change_col] = f'{change:.0f}%'
pd.set_option("display.max_rows", None, "display.max_columns", None)
print(df)
Второе решение (со значениями 0 или None в исходном df):
import pandas as pd
data = {
'Group': ['Group A', 'Group A', 'Group B', 'Group B'],
'Subgroup': ['Sub A', 'Sub B', 'Sub A', 'Sub B'],
'Pre-Product-1': [100, 50, 60, 40],
'Post-Product-1': [150, 70, 20, 10],
'Product-1-Change': [0, 0, 0, 0],
'Pre-Product-2': [100, 50, 60, 40],
'Post-Product-2': [150, 70, 10, 10],
'Product-2-Change': [0, 0, 0, 0]
}
df = pd.DataFrame(data)
for i in range(1, 3):
'''Loop over each product and assign percentage change to the "change_col" column and use % notation'''
pre_col = f'Pre-Product-{i}'
post_col = f'Post-Product-{i}'
change_col = f'Product-{i}-Change'
df[change_col] = (round(((df[post_col] - df[pre_col]) / df[pre_col] * 100), 2)).astype(str) + '%'
pd.set_option("display.max_rows", None, "display.max_columns", None)
print(df)
Третье решение (со значениями 0 или None в исходном df):
import pandas as pd
data = {
'Group': ['Group A', 'Group A', 'Group B', 'Group B'],
'Subgroup': ['Sub A', 'Sub B', 'Sub A', 'Sub B'],
'Pre-Product-1': [100, 50, 60, 40],
'Post-Product-1': [150, 70, 20, 10],
'Product-1-Change': [None,None,None,None],
'Pre-Product-2': [100, 50, 60, 40],
'Post-Product-2': [150, 70, 10, 10],
'Product-2-Change': [0,0,0,0]
}
df = pd.DataFrame(data)
def calc_pct_change(pre, post):
'''Define a function to calculate percentage change + use the % notation'''
return [f"{(b-a)/a*100:.0f}%" for a, b in zip(pre, post)]
for i, row in df.iterrows():
'''
Loop over each row and calculate percentage change
Get the product number from the pre column name
Update the value in the existing 'Product-i-Change' column
'''
pre_cols = [col for col in df.columns if col.startswith('Pre')]
post_cols = [col for col in df.columns if col.startswith('Post')]
for pre_col, post_col in zip(pre_cols, post_cols):
pre = row[pre_col]
post = row[post_col]
change = calc_pct_change([pre], [post])[0]
product_num = pre_col.split('-')[2]
product_change_col = f"Product-{product_num}-Change"
df.loc[i, product_change_col] = change
print("row", row)
pd.set_option("display.max_rows", None, "display.max_columns", None)
print(df)
Рассмотрите возможность изменения структуры вашего фрейма данных, чтобы сделать его более согласованным с базовой логикой. Тогда будет легко вычислить нужные вам значения без цикла.
На вашем примере:
import pandas as pd
df = pd.DataFrame({'Group': ['Group A', 'Group A', 'Group B', 'Group B'],
'Subgroup': ['Sub A', 'Sub B', 'Sub A', 'Sub B'],
'pre_product_A': [100, 50, 60, 40],
'post_product_A': [150, 70, 20, 10],
'pre_product_B': [100, 50, 60, 40],
'post_product_B': [150, 70, 70, 10]})
df.set_index(['Group', 'Subgroup'], inplace=True)
products = ['A', 'B']
phases = ['pre', 'post']
df.columns = pd.MultiIndex.from_product([products, phases],
names=['product', 'phase'])
df = df.stack(level='product')
df['change'] = 100 * df.post // df.pre - 100
print(df)
phase post pre change
Group Subgroup product
Group A Sub A A 150 100 50
B 150 100 50
Sub B A 70 50 40
B 70 50 40
Group B Sub A A 20 60 -67
B 70 60 16
Sub B A 10 40 -75
B 10 40 -75
Я попробовал первое решение, и оно дает мне результат, который я хочу, но по какой-то причине он возвращает результаты только для последнего продукта в моем списке продуктов.