将函数应用于 pandas 数据帧的每一行,但工作不太正常

Applying a function to each row of a pandas dataframe, not working quite right

提问人:user22908408 提问时间:11/13/2023 更新时间:11/13/2023 访问量:57

问:

我对熊猫生疏了,请温柔一点!

我有一个数据帧,它是 (349, 17) 各种水样值(pH、盐度、温度等)。我正在使用 PyCO2SYS 工具箱来计算化学输出。我创建了一个函数,该函数应使用数据帧行索引,从与行关联的指定列中提取变量,并返回所需的变量(使用 PyCO2SYS)。

函数如下:

def pCO2_column(i):
# input variables
    PAR1 = df['TA (umol/kg)'][i]        # ALK
    PAR2 = df['pH'][i]                  # pH                                  
    SAL = df['Sal psu'][i]              # Salinity
    TEMPIN = df['Temp C'][i]            # Temperature (input)
    TEMPOUT = TEMPIN                    # Temperature (output)
    PRESIN = df['Pressure psi a'][i]    # Pressure (input)
    PRESOUT = PRESIN                    # Pressure (output)
# Result I want to add into column
    pCO2_out = pyco2.sys(PAR1, PAR2, PAR1TYPE, PAR2TYPE, SAL, TEMPIN, TEMPOUT, PRESIN, PRESOUT, pHSCALEIN, K1K2CONSTANTS, KSO4CONSTANTS)["pCO2_out"]
    return pCO2_out

注意:其他参数是全局定义的;函数中的那些是将随每一行而变化的那些

我想对每个行索引使用此函数,以创建我想要的值的列。我已经能够以一种笨拙的方式做到这一点,但我想优化它。我这样做的一种方法是根据该索引将我的函数应用于每一行:

df['pCO2_out (μatm)'] = df.apply(lambda row: pCO2_column(df.index), axis=0)

但是,当我第一次运行它时,它给了我以下错误: ValueError: Wrong number of items passed 17, placement means 1
如果我将其更改为 axis=1,则每行都包含数组中为所有行计算的每个有价值的内容。
https://i.stack.imgur.com/5QaMH.png
如果我将其改回 axis=0,它会正确填充,每行中只有一个唯一值。 (https://i.stack.imgur.com/qkaAM.png
我知道我还可以遍历每一行,用值填充数组,然后将该数组作为新列插入......

这看起来非常简单,但我不知道我哪里出错了。有什么建议吗?

蟒蛇 熊猫 numpy

评论


答:

0赞 Suraj Shourie 11/13/2023 #1

您错误地构建了 lambda 函数,请查看文档或在线查看一些示例。

具体来说,您不需要按索引进行迭代,因为您已经获得了每一行。要使用最小示例修复代码,请参阅以下内容:axis=1

df_p = pd.DataFrame({'pH':np.random.random(10)})
def pCO2_column(row):
# input variables
    PAR2 = row['pH']
    return PAR2
df_p.apply(pCO2_column, axis=1)

请注意,我不需要行索引,只需选择列作为行将是一个系列

0赞 JNevill 11/13/2023 #2

使用迭代数据帧来运行函数,其中仅传递索引,然后在迭代函数中查询日期帧是非常昂贵且不必要的。apply()

相反,您可以将整行传递给 apply 中的函数:

def pCO2_column(row):
# input variables
    PAR1 = row['TA (umol/kg)']       # ALK
    PAR2 = row['pH']                 # pH                                  
    SAL = row['Sal psu']             # Salinity
    TEMPIN = row['Temp C']           # Temperature (input)
    TEMPOUT = TEMPIN                 # Temperature (output)
    PRESIN = row['Pressure psi a']   # Pressure (input)
    PRESOUT = PRESIN                 # Pressure (output)
# Result I want to add into column
    pCO2_out = pyco2.sys(PAR1, PAR2, PAR1TYPE, PAR2TYPE, SAL, TEMPIN, TEMPOUT, PRESIN, PRESOUT, pHSCALEIN, K1K2CONSTANTS, KSO4CONSTANTS)["pCO2_out"]
    return pCO2_out

df['pCO2_out (μatm)'] = df.apply(lambda row: pCO2_column(row), axis=1)
0赞 some3128 11/13/2023 #3

下面的例子有效吗?它一次性提供所有行。pyco2.sys

import pandas as pd

#Synthetic data
df = pd.DataFrame(
    {'chlor': [2, 1, 1],
     'cond': [11, 23, 44],
     'depth': [33, 55, 77]},
)
df

#Mock implementation. Replace with actual import.
class pyco2:
    def __init__(self):
        pass
    def sys(par1, par2, par3):
        return par1 * par2 / par3

#Create new col in one go
# p2co2.sys docs say it accepts arrays for each argument,
# so you can feed all rows in at once
df['pCO2_out (uatm)'] = pyco2.sys(par1=df['chlor'], par2=df['cond'], par3=df['depth'])
df

enter image description here