Операции по строкам во фрейме данных

Я работаю над фреймом данных, это мой вклад:

df=pd.DataFrame({'A':[5,3,2],'B':[2,1,1],
              'a':[2,3,1],'b':[1,3,8]})

Ожидаемый результат:

pd.DataFrame({'A':[5,3,2],'B':[2,1,1],
              'a':[2,3,1],'b':[1,3,8],
             'A*a':[10,9,2],'B*b':[2,3,8],
              'Max':[10,9,8]})

Моя цель — умножить столбцы отдельно, например, A*a, B*b. Последняя интересующая меня переменная — «Max», которая возвращает максимальное значение Aa и Bb.

Обратите внимание, что у меня больше двух пар, мои реальные данные содержат десятки столбцов, поэтому мне нужно сделать это в масштабе. В идеале я хочу структурировать функцию и взять карту ({A:a,B:b,C:c...}) в качестве входных данных, запустить эту функцию в каждой строке фрейма данных и вернуть значение Max.

Я попробовал это, но не получилось:

dic = {'A':'a','B':'b'}


def score(row):
    
    max_score=0
    
    for i,j in dic.items():
        
        if row[i]*row[j]>max_score:
            
            max_score=row[i]*row[j]
    
    return max_score

df.apply(score)

карта предопределена? или динамически создается?

iBeMeltin 27.06.2024 16:55

Я отредактировал свой вопрос, он должен быть заранее определен.

Derek 27.06.2024 16:56
Почему в 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 может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
2
61
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Ты можешь сделать:

d = {"A":"a","B":"b"}
out = pd.DataFrame(
    {k+"*"+v: df[k].mul(df[v]) for k, v in d.items()}
)
out["Max"] = out.max(axis=1)
out = pd.concat([df, out], axis=1)

print(out)


   A  B  a  b  A*a  B*b  Max
0  5  2  2  1   10    2   10
1  3  1  3  3    9    3    9
2  2  1  1  8    2    8    8

Я предлагаю два варианта, удачно названных «вариант1» и «вариант2».

Вариант 1, возможно, более читаем. Вы проходите все сопряжения и создаете новые столбцы. Затем вы создаете столбец max и возвращаете новый df.

def option1(df: pd.DataFrame, d:dict) -> pd.DataFrame:

    new_cols = []
    for i,j in d.items():
        new_col = f'{i}{j}'
        df[new_col] = df[i]*df[j]
        new_cols.append(new_col)

    df['max'] = df[new_cols].to_numpy().max(axis=1)
    return df

Вариант 2 немного больше полагается на numpy, поэтому, если ваш набор данных большой, он может быть лучше. Он вычисляет все умножения за один раз и сразу после этого делает максимальное.

def option2(df: pd.DataFrame, d:dict) -> pd.DataFrame:
    i1 = list(d)
    i2 = list(d.values())
    new_data = df[i1].to_numpy()*df[i2].to_numpy()
    max_col = new_data.max(axis=1)
    new_cols = [f'{i}{j}' for i,j in zip(i1,i2)]
    df[new_cols] = new_data
    df['max'] = max_col

    return df

Executing both functions 1000 times here are the timings:
option1: 0.786 s
option2: 0.678 s

Кажется, что вариант 2 работает быстрее даже с этим небольшим набором данных.

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

Одним из вариантов может быть выполнение векторного умножения:

dic = {'A':'a','B':'b'}

# multiply keys/values
tmp = df[list(dic)].mul(df[dic.values()].values)
# update column names
tmp.columns += '*' + pd.Index(dic.values())
# compute max
tmp['max'] = tmp.max(axis=1)

out = df.join(tmp)

Выход:

   A  B  a  b  A*a  B*b  max
0  5  2  2  1   10    2   10
1  3  1  3  3    9    3    9
2  2  1  1  8    2    8    8

Другой вариант — переименовать и groupby.prod:

dic = {'A':'a','B':'b'}

tmp = (df.rename(columns=dic).add_suffix('_prod')
       .groupby(axis=1, level=0).prod()
      )

out = df.join(tmp.assign(max=tmp.max(axis=1)))

Для последних версий панд:

dic = {'A':'a','B':'b'}

tmp = (df.rename(columns=dic).add_suffix('_prod')
       .T.groupby(level=0).prod().T
      )

out = df.join(tmp.assign(max=tmp.max(axis=1)))

Выход:

   A  B  a  b  a_prod  b_prod  max
0  5  2  2  1      10       2   10
1  3  1  3  3       9       3    9
2  2  1  1  8       2       8    8

Если пары всегда в верхнем и нижнем регистре, это должно работать:

df.join(
    pd.concat(
        [df[c].mul(df[c.lower()]).rename('{}*{}'.format(c,c.lower())) for c in df.columns if c.isupper()],axis=1)
        .assign(
            Max = lambda x: x.max(axis=1))

Выход:

   A  B  a  b  A*a  B*b  Max
0  5  2  2  1   10    2   10
1  3  1  3  3    9    3    9
2  2  1  1  8    2    8    8

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