Как избежать повторения с помощью функции применить

#python-3.x

Вопрос:

У меня есть фрейм данных с именем new_data , содержащий два списка столбцов :

 l = ["l_1stIn","l_1stWon", "l_2ndWon","l_ace", "l_bpFaced","l_df","l_age","l_rank_gap","l_rank_points","l_1stIn"]

w = ["w_1stIn","w_1stWon", "w_2ndWon","w_ace", "w_bpFaced","w_df", "w_age","w_rank_gap","w_rank_points","w_1stIn"]
 

Я хочу создать новый фрейм данных с новыми столбцами, которые являются результатом разницы между
двумя списками столбцов, указанными ниже :

 loss['1stIn'] = new_data.apply(lambda x: f(x.l_1stIn, x.w_1stIn), axis=1)
loss['1stWon'] = new_data.apply(lambda x: f(x.l_1stWon, x.w_1stWon), axis=1)
loss['2ndWon'] = new_data.apply(lambda x: f(x.l_2ndWon, x.w_2ndWon), axis=1)
loss['ace'] = new_data.apply(lambda x: f(x.l_ace, x.w_ace), axis=1)
loss['bpFaced'] = new_data.apply(lambda x: f(x.l_bpFaced, x.w_bpFaced), axis=1)
loss['df'] = new_data.apply(lambda x: f(x.l_df, x.w_df), axis=1)
loss['age'] = new_data.apply(lambda x: f(x.l_age, x.w_age), axis=1)
loss['ht'] = new_data.apply(lambda x: f(x.l_ht, x.w_ht), axis=1)
loss['rank_gap'] = new_data.apply(lambda x: f(x.l_rank_gap, x.w_rank_gap), axis=1)
loss['rank_points'] = new_data.apply(lambda x: f(x.l_rank_points, x.w_rank_points), axis=1)
loss['1stIn'] = new_data.apply(lambda x: f(x.l_1stIn, x.w_1stIn), axis=1)
 

Итак, я хочу создать новый loss фрейм данных, как указано ниже, но без многократного повторения функции apply. Я ищу общую функцию, которая имеет в качестве входных данных три списка :

 l = ["l_1stIn","l_1stWon", "l_2ndWon","l_ace", "l_bpFaced","l_df","l_age","l_rank_gap","l_rank_points","l_1stIn"]

w = ["w_1stIn","w_1stWon", "w_2ndWon","w_ace", "w_bpFaced","w_df","w_age","w_rank_gap","w_rank_points","w_1stIn"]

output = ["1stIn","1stWon", "2ndWon","ace",
 "bpFaced","df","age", "rank_gap","rank_points","1stIn"]
 

и возвращает конечный фрейм данных loss output , содержащий столбцы as, который является результатом разницы между l и w

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

1. Написать такую функцию не так уж сложно. Вы знаете , что вы можете получить доступ к столбцам фрейма данных с помощью обозначения индекса: когда вы это сделаете col = "l_1stIn" , вам df[col] будет предоставлен этот столбец фрейма данных. Теперь примените эту идею к каждому новому столбцу, который вы хотите. Как только вы попытаетесь, задайте конкретный вопрос о своем коде.

2. @PranavHosangadi, я новичок в python, и я ищу решение для оптимизации, чтобы избежать повторения каждый раз. Я посмотрю, как это можно сделать, используя индекс, как вы предложили. Спасибо вам в любом случае

Ответ №1:

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

 def do_calculation(col0, col1):
    # Do something with both columns and then return the result
    # For example,
    return col0 - col1
 

Затем давайте напишем функцию, которая будет принимать множество входных и выходных столбцов и вызывать doCalculation() их с правильными входными данными.

 def process_data(func, data, inputs_0, inputs_1, outputs):
    df = pd.DataFrame()
    # zip to iterate over all three lists together
    for col_in0, col_in1, col_out in zip(inputs_0, inputs_1, outputs):
        in0 = data[col_in0] # Get the first input col
        in1 = data[col_in1] # Second input col
        df[col_out] = func(in0, in1) # Call the given func and set its output as the output column

    return df
 

И, наконец, давайте создадим фиктивный фрейм данных и вызовем эту функцию:
В моем фрейме данных каждая строка описывает банковский счет и содержит четыре столбца: Предыдущий баланс , сумма для списания, возраст владельца на данный момент и возраст владельца на момент открытия счета. Мы собираемся рассчитать текущий баланс и количество лет, в течение которых они держали счет.

 import io
csvtext="""old_balance,debit_amount,age_current,age_start
100,20,50,45
500,10,30,10
200,100,80,30"""
in_df = pd.read_csv(io.StringIO(csvtext)) # Read the dataframe
 
    old_balance  debit_amount  age_current  age_start
0          100            20           50         45
1          500            10           30         10
2          200           100           80         30
 

Если бы вы делали это, используя свой метод, вы бы сделали:

 df = pd.DataFrame()
df['new_balance'] = in_df.apply(lambda x: x.old_balance - x.debit_amount, axis=1)
df['customer_for'] = in_df.apply(lambda x: x.age_current - x.age_start, axis=1)
 

что дает:

    new_balance  customer_for
0           80             5
1          490            20
2          100            50
 

Чтобы вызвать нашу функцию, нам нужно предоставить ей функцию, которая выполняет вычисления, входные данные, входные столбцы

 inputs_0 = ["old_balance", "age_current"]
inputs_1 = ["debit_amount", "age_start"]
outputs = ["new_balance", "customer_for"]

df = process_data(do_calculation, in_df, inputs_0, inputs_1, outputs)
 

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

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

1. спасибо за это решение, но я получил эту ошибку : NameError: name 'col_in0' is not defined

2. @Rпрограммист Ой, опечатка. Измените строку на for col_in0, col_in1, col_out in zip(inputs_0, inputs_1, outputs):

3. Я пытался for col_in0, col_in1, col_out in zip(inputs_0, inputs_1, outputs): , но ни за что

4. Что ты имеешь в виду? Я обновил код в своем ответе, чтобы исправить эту опечатку.