Вычислить процентное изменение между двумя столбцами, используя цикл for

Группа Подгруппа pre_product_A post_product_A product_A_Change pre_product_B post_product_B product_B_Change Группа А Саб А 100 150 50% 100 150 50% Группа А Саб Б 50 70 40% 50 70 40% Группа Б Саб А 60 20 -67% 60 70 -67% Группа Б Саб Б 40 10 -75% 40 10 -75%

У меня есть фрейм данных, который показывает группу, подгруппу, предварительные и пост-цифры для каждого продукта.

Я хочу рассчитать процентное изменение для каждого продукта (как показано в столбцах 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()
Почему в 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
0
92
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Если все ваши столбцы имеют одинаковые имена: 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) 

Я попробовал первое решение, и оно дает мне результат, который я хочу, но по какой-то причине он возвращает результаты только для последнего продукта в моем списке продуктов.

allthelemons 31.03.2023 04:01

Что ты имеешь в виду? я не уверен, что понимаю

Florent Monin 31.03.2023 10:17

В моем списке есть продукт A, продукт B и т. д. вплоть до продукта F, например. Но когда я запускаю свой скрипт, он показывает результаты только для продукта F, а не для всех продуктов в моем списке.

allthelemons 03.04.2023 02:22
Ответ принят как подходящий

Вот моя попытка:

#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

Это дало мне именно то, что я хотел, с небольшими корректировками. Поскольку у меня уже был фрейм данных, на который я хотел сослаться, я просто заменил часть «данные» своим фактическим фреймом данных. Я также хотел сохранить свои первые два столбца «Группа» и «Подгруппа», поэтому я добавил эти два столбца в свой список столбцов. Спасибо!!

allthelemons 03.04.2023 03:39

Хорошо, но ваш запрос не совсем ясен... Вы используете списки 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

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