pandas:对DataFrame行进行复杂过滤

duc*_*thd 78 python pandas

我想通过每行的函数来过滤行,例如

def f(row):
  return sin(row['velocity'])/np.prod(['masses']) > 5

df = pandas.DataFrame(...)
filtered = df[apply_to_all_rows(df, f)]
Run Code Online (Sandbox Code Playgroud)

或者对于另一个更复杂,人为的例子,

def g(row):
  if row['col1'].method1() == 1:
    val = row['col1'].method2() / row['col1'].method3(row['col3'], row['col4'])
  else:
    val = row['col2'].method5(row['col6'])
  return np.sin(val)

df = pandas.DataFrame(...)
filtered = df[apply_to_all_rows(df, g)]
Run Code Online (Sandbox Code Playgroud)

我怎么能这样做?

duc*_*thd 109

您可以使用DataFrame.apply,沿给定轴应用函数,

In [3]: df = pandas.DataFrame(np.random.randn(5, 3), columns=['a', 'b', 'c'])

In [4]: df
Out[4]: 
          a         b         c
0 -0.001968 -1.877945 -1.515674
1 -0.540628  0.793913 -0.983315
2 -1.313574  1.946410  0.826350
3  0.015763 -0.267860 -2.228350
4  0.563111  1.195459  0.343168

In [6]: df[df.apply(lambda x: x['b'] > x['c'], axis=1)]
Out[6]: 
          a         b         c
1 -0.540628  0.793913 -0.983315
2 -1.313574  1.946410  0.826350
3  0.015763 -0.267860 -2.228350
4  0.563111  1.195459  0.343168
Run Code Online (Sandbox Code Playgroud)

  • 在这种情况下不需要"申请".常规布尔索引可以正常工作.`df [df ['b]> df ['c']]`.很少有情况需要`apply`,甚至很少需要`axis = 1` (14认同)

Cha*_*She 12

假设我有一个DataFrame,如下所示:

In [39]: df
Out[39]: 
      mass1     mass2  velocity
0  1.461711 -0.404452  0.722502
1 -2.169377  1.131037  0.232047
2  0.009450 -0.868753  0.598470
3  0.602463  0.299249  0.474564
4 -0.675339 -0.816702  0.799289
Run Code Online (Sandbox Code Playgroud)

我可以使用sin和DataFrame.prod来创建一个布尔掩码:

In [40]: mask = (np.sin(df.velocity) / df.ix[:, 0:2].prod(axis=1)) > 0

In [41]: mask
Out[41]: 
0    False
1    False
2    False
3     True
4     True
Run Code Online (Sandbox Code Playgroud)

然后使用掩码从DataFrame中进行选择:

In [42]: df[mask]
Out[42]: 
      mass1     mass2  velocity
3  0.602463  0.299249  0.474564
4 -0.675339 -0.816702  0.799289
Run Code Online (Sandbox Code Playgroud)

  • 实际上,这可能是一个不好的例子:`np.sin`自动广播到所有元素.如果我用一个只能一次处理一个输入的不太智能的功能替换它会怎么样? (2认同)

cgl*_*cet 5

我不能评论duckworthd的回答,但它并不完美。当数据框为空时它会崩溃:

df = pandas.DataFrame(columns=['a', 'b', 'c'])
df[df.apply(lambda x: x['b'] > x['c'], axis=1)]
Run Code Online (Sandbox Code Playgroud)

输出:

ValueError: Must pass DataFrame with boolean values only
Run Code Online (Sandbox Code Playgroud)

对我来说,它看起来像是 Pandas 中的一个错误,因为 { } 绝对是一组有效的布尔值。有关解决方案,请参阅Roy Hyunjin Han 的回答


Roy*_*Han 5

指定reduce=True还要处理空的DataFrame。

import pandas as pd

t = pd.DataFrame(columns=['a', 'b'])
t[t.apply(lambda x: x['a'] > 1, axis=1, reduce=True)]
Run Code Online (Sandbox Code Playgroud)

https://crosscompute.com/n/jAbsB6OIm6oCCJX9PBIbY5FECFKCClyV/-/apply-custom-filter-on-rows-of-dataframe


use*_*965 5

我发现的最好方法是,不要使用reduce=True来避免空 df 的错误(因为无论如何都不推荐使用此 arg),只需在应用过滤器之前检查 df size > 0:

def my_filter(row):
    if row.columnA == something:
        return True

    return False

if len(df.index) > 0:
    df[df.apply(my_filter, axis=1)]
Run Code Online (Sandbox Code Playgroud)