管道中的函数式编程和python pandas数据帧

use*_*546 2 python functional-programming pipeline dataframe pandas

我想知道哪种函数式编程的最佳实践是编写一系列函数来处理熊猫数据框-或任何其他可变输入类型-作为函数的输入。

这里有两个想法,但是希望有更好的东西:)

想法#1-不进行功能编程而是节省内存

def foo(df, param):
    df['col'] = df['col'] + param

def pipeline(df):
    foo(df, 1)
    foo(df, 2)
    foo(df, 3)
Run Code Online (Sandbox Code Playgroud)

想法#2-更多的功能编程,但是通过执行.copy()浪费了内存

def foo(df, param):
    df = df.copy()
    df['col'] = df['col'] + param
    return df

def pipeline(df):
    df1 = foo(df, 1)
    df2 = foo(df1, 2)
    df3 = foo(df2, 3)
Run Code Online (Sandbox Code Playgroud)

T B*_*gis 5

您可以链接在数据帧上运行的函数调用。还可以看看DataFrame.pipe熊猫。像这样,添加了两个非foo操作:

df = (df.pipe(foo,1)
      .pipe(foo,2)
      .pipe(foo,3)
      .drop(columns=['drop','these'])
      .assign(NEW_COL=lambda x: x['OLD_COL'] / 10))
Run Code Online (Sandbox Code Playgroud)

df将是foo您使用时传递给它的第一个参数pipe


Elm*_*80s 4

如果您的数据框是一维的(即它是一个项目列表),那么您可以一次完成所有操作,而不是应用多个“管道”。例如我们有一个数据框

>>> table
     Name  Year of Birth      City
0    Mike           1970  New York
1   Chris           1981     Miami
2  Janine           1975   Seattle
Run Code Online (Sandbox Code Playgroud)

我们想要计算年龄并检查一个人是否住在迈阿密。您可以应用 2 个管道,但也可以使用单个 lambda 来完成:

>>> f = lambda s: pd.Series([2019 - s['Year of Birth'], s['City'] == 'Miami'])
Run Code Online (Sandbox Code Playgroud)

然后应用它

>>> table[['Age', 'Lives in Miami']] = table.apply(f, axis=1)
>>> table
     Name  Year of Birth      City  Age  Lives in Miami
0    Mike           1970  New York   49           False
1   Chris           1981     Miami   38            True
2  Janine           1975   Seattle   44           False
Run Code Online (Sandbox Code Playgroud)

所有工作均在 中完成f

另一个例子:假设您想检查谁的年龄超过 45 岁。这包含两个串行操作(前面的示例是 2 个并行操作):

  1. 计算年龄
  2. 检查年龄是否大于45岁

您可以使用 2 个管道,但同样可以通过应用单个 lambda 来完成这一切:

>>> table
     Name  Year of Birth      City   
0    Mike           1970  New York            
1   Chris           1981     Miami           
2  Janine           1975   Seattle      
>>> g = lambda s: pd.Series([2019 - s['Year of Birth'] > 45])              
>>> table['Older than 45'] = table.apply(g, axis=1)
>>> table
     Name  Year of Birth      City  Older than 45
0    Mike           1970  New York           True
1   Chris           1981     Miami          False
2  Janine           1975   Seattle          False
Run Code Online (Sandbox Code Playgroud)

如果您喜欢不变性,那么就这样做

>>> table
     Name  Year of Birth      City
0    Mike           1970  New York
1   Chris           1981     Miami
2  Janine           1975   Seattle 
>>> pd.concat([table, table.apply(f, axis=1)], axis=1)
     Name  Year of Birth      City   0      1
0    Mike           1970  New York  49  False
1   Chris           1981     Miami  38   True
2  Janine           1975   Seattle  44  False
Run Code Online (Sandbox Code Playgroud)

如果你不喜欢 lambda 则定义

def f(s):
    return pd.Series([2019 - s['Year of Birth'], 
                      s['City'] == 'Miami'])
Run Code Online (Sandbox Code Playgroud)

仅当您想要应用仅需要在单个行上工作的映射时,这一切才有效。另外,我没有对速度做出任何声明,管道可能会更快,但是这是非常可读的。

(最后你意识到你最好使用 Haskell。)