【问题标题】:Pandas: How to use applymap/apply function with arguements to a dataframe without loopingPandas:如何在不循环的情况下使用带有参数的 applymap/apply 函数到数据帧
【发布时间】:2021-05-09 12:36:43
【问题描述】:

背景

Link 1 表明 apply 可以应用于系列。我想在 DataFrame 的子集上使用 apply 函数,而不需要遍历列。

示例代码

创建大小为 7、7 的示例 DataFrame

def f_test_df(n_rows, n_cols):
    df1 = pd.DataFrame(np.random.rand(n_rows, n_cols))
    df = df1.applymap(lambda x: round(x*10))
    return df 

np.random.seed(seed=1)
df1 = f_test_df(7, 7)

如果数字在预定义的范围内,则所需的函数应该返回相同的值,否则根据它是在限制的下限还是上限,应该返回相应的值。要应用的函数如下:

def f_bounds(x, lower, upper):
    if x < lower:
        return 'lower'
    elif x > upper:
        return 'upper'
    else:
        return x

需要应用函数的 DataFrame 的选定部分

df1.loc[2:5, 2:5]

应用函数:

lower = 2
upper = 5
df1.loc[2:5, 2:5].apply(f_bounds, args=(lower, upper))

我遇到了以下错误:

ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().

因此,我改变了方法并使用了跨列循环,如下所示(效果很好):

for j in range(2, 5):
    print(df1.loc[2:5, j].apply(f_bounds, args=(lower, upper)))

其他未经测试的方法

Link 2 此处参考答案 2,建议不要将 applymap 与参数一起使用。所以,我没有使用applymap,因为该函数需要两个额外的参数。读者请注意,applymap已在答案中使用。

期望的结果

我想实现这个需要争论的功能,而不是将列循环到数据框。

【问题讨论】:

  • 你可以试试df.applymap
  • applymap 不支持函数所需的参数。因此,我无法使用它。
  • df1.loc[2:5, 2:5].applymap(lambda x: f_bounds(x, lower, upper))
  • 谢谢。我不知道此更新。
  • 更新了我的答案以展示另一种方法

标签: python pandas arguments apply python-applymap


【解决方案1】:

您可以直接使用 applymap 和 lambda 函数,该函数接受 DataFrame 窗口上的参数。然后可以直接更新视图来更新原来的DataFrame -

df1.loc[2:5, 2:5] = df1.loc[2:5, 2:5].applymap(lambda x: f_bounds(x, lower, upper))
print(df1)
    0  1      2      3      4      5  6
0   4  7      0      3      1      1  2
1   3  4      5      4      7      2  9
2   0  7      4  upper  lower      2  8
3  10  3  upper  upper  upper  lower  0
4   2  9  lower      4  upper      5  7
5   3  7  upper  lower  upper  upper  7
6   3  8      1      4      9      3  3

编辑:

这是不使用 apply 或 applymap 的另一种方法

cond1 = df1[(df1.loc[2:5, 2:5]<lower)].notna()
cond2 = df1[(df1.loc[2:5, 2:5]>upper)].notna() 
df1_new = df1.where(~cond1, 'lower').where(~cond2, 'upper')
print(df1_new)
    0  1      2      3      4      5  6
0   4  7      0      3      1      1  2
1   3  4      5      4      7      2  9
2   0  7      4  upper  lower      2  8
3  10  3  upper  upper  upper  lower  0
4   2  9  lower      4  upper      5  7
5   3  7  upper  lower  upper  upper  7
6   3  8      1      4      9      3  3

【讨论】:

    【解决方案2】:

    您可以将stack 与unstack 一起使用:

    lower = 2
    upper = 5
    a = df1.loc[2:5, 2:5].stack().apply(f_bounds, args=(lower, upper)).unstack()
    print (a)
           2      3      4      5
    2      4  upper  lower      2
    3  upper  upper  upper  lower
    4  lower      4  upper      5
    5  upper  lower  upper  upper
    

    或者将DataFrame传递给函数:

    def f_bounds(x, lower, upper):
        m1 = x < lower
        m2 = x > upper
        
        return np.select([m1, m2], ['lower', 'upper'], default=x)
    
        
    lower = 2
    upper = 5
    a = pd.DataFrame(f_bounds(df1.loc[2:5, 2:5], 2 ,5),
                     index=df1.index[2:6],
                     columns = df1.columns[2:6])
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-18
      • 2017-09-14
      相关资源
      最近更新 更多