【问题标题】:Pandas applying with multi-indexed columnsPandas 应用多索引列
【发布时间】:2021-11-20 22:16:17
【问题描述】:

我有以下工作代码,可以创建一些简单的数学函数和一个带有多索引列的 DataFrame。我想有条件地对其应用一些功能。

import pandas as pd
import numpy as np

# Simple maths functions  ---
def add(scalars): return sum(scalars)  #Adds every element in scalars
def sub(scalars): return (scalars[0] - sum(scalars[1:])) #First scalar value subtracted by the rest of the scalar list
def mul(scalars): return np.prod(scalars) #Multiplies every element in scalars
def divi(scalars): return (scalars[0] / np.prod(scalars[1:])) #First scalar value divided by the rest product of the scalar list

# Create df ---

operatorList = [add, sub, mul, divi]  # List of our maths functions
names = ['add', 'sub', 'mul', 'divi'] # List of the names of our maths functions
size = 4

tups = [('scalars', 'add', 'sc0'), ('scalars', 'add', 'sc1'), ('scalars', 'add', 'sc2'), ('scalars', 'sub', 'sc0'), ('scalars', 'sub', 'sc1'), ('scalars', 'mul', 'sc0'), ('scalars', 'mul', 'sc1'), ('scalars', 'mul', 'sc2'), ('scalars', 'divi', 'sc0'), ('scalars', 'divi', 'sc1'), ('operator', '', '')]
df = pd.DataFrame(columns=pd.MultiIndex.from_tuples(tups))

df['operatorIndex'] = np.random.randint(0, len(names), size)
df['operator'] = df['operatorIndex'].apply(lambda x: str(names[x]))

groupSize = 2
df['ID']=np.divmod(np.arange(len(df)),groupSize)[0]+1
df.set_index('ID', inplace=True)
df.sort_index(inplace=True)

for name in names:
  df.loc[(df['operator'] == name), ('scalars', name, df.columns.levels[2])] = np.random.randint(0, 10)
> df

    scalars                                   operator  operatorIndex
    add         sub     mul         divi        
    sc0 sc1 sc2 sc0 sc1 sc0 sc1 sc2 sc0 sc1     
ID                                              
1   4   4   4   NaN NaN NaN NaN NaN NaN NaN   add       0
1   NaN NaN NaN 7   7   NaN NaN NaN NaN NaN   sub       1
2   NaN NaN NaN NaN NaN 3   3   3   NaN NaN   mul       2
2   NaN NaN NaN 7   7   NaN NaN NaN NaN NaN   sub       1

如何创建一个名为Evaluation 的新列,它是每列的正确数学函数的结果? operator 列告诉每一行需要应用哪个函数。

示例目标 df 如下所示:

> df

    scalars                                   operator  operatorIndex  Evaluation
    add         sub     mul         divi        
    sc0 sc1 sc2 sc0 sc1 sc0 sc1 sc2 sc0 sc1     
ID                                              
1   4   5   6   NaN NaN NaN NaN NaN NaN NaN   add       0              15
1   NaN NaN NaN 7   2   NaN NaN NaN NaN NaN   sub       1              5
2   NaN NaN NaN NaN NaN 1   2   3   NaN NaN   mul       2              6
2   NaN NaN NaN 5   9   NaN NaN NaN NaN NaN   sub       1              -4

【问题讨论】:

  • 您在一个问题中提出了两个问题 - 请针对每个问题提出两个单独的 SO 问题。 :)

标签: python pandas dataframe numpy


【解决方案1】:

这样就可以了:

df['Evaluation'] = df['operatorIndex'].apply(lambda operatorIndex: operatorList[operatorIndex](df['scalars'][names[operatorIndex]].min()))

虽然它只有在每个运算符只有一个条目时才有效 - 如果一个操作在 df 中有多行,它会产生奇怪的结果。

您可以通过存储为每一行更新的全局计数器并使用iloc 按索引访问标量行来解决此问题:

rowCounter = -1
def func(operatorIndex):
    global rowCounter
    rowCounter += 1
    return operatorList[operatorIndex](df['scalars'][names[operatorIndex]].iloc[rowCounter])

df['Evaluation'] = df['operatorIndex'].apply(func)

【讨论】:

  • 每个运算符会有很多行,所以我不能使用第一个选项。我也不太热衷于使用全局计数器。不过,我很欣赏这种努力。不过,我正在尝试将您的第一次尝试改编成某种东西。我有一种预感,apply() 参与其中,但我无法同时获得operatorIndex 和标量。感觉我几乎必须在另一个 apply() 中使用 apply()
  • 我已经修改了你的答案。我认为它现在功能齐全。让我知道它是否经得起审查。感谢您的帮助:)
【解决方案2】:

设法调整来自@user17242583 的答案

df['Evaluation'] = df.apply(lambda row: operatorList[row['operatorIndex'].values[0]](row['scalars'][names[row['operatorIndex'].values[0]]].to_numpy()) , axis=1 )

我不知道这是否对其他人有用,但你去吧。

【讨论】:

    猜你喜欢
    • 2016-12-16
    • 2021-12-12
    • 2017-03-04
    • 2020-08-31
    • 2014-07-10
    • 2021-09-23
    • 2021-12-17
    • 2014-04-10
    • 2018-10-12
    相关资源
    最近更新 更多