在具有多个 if 语句的 Pandas Lambda 函数中使用 Apply

Posted

技术标签:

【中文标题】在具有多个 if 语句的 Pandas Lambda 函数中使用 Apply【英文标题】:Using Apply in Pandas Lambda functions with multiple if statements 【发布时间】:2018-07-30 01:06:41 【问题描述】:

我正在尝试根据这样的数据框中的人的大小来推断分类:

      Size
1     80000
2     8000000
3     8000000000
...

我希望它看起来像这样:

      Size        Classification
1     80000       <1m
2     8000000     1-10m
3     8000000000  >1bi
...

我知道理想的过程是应用这样的 lambda 函数:

df['Classification']=df['Size'].apply(lambda x: "<1m" if x<1000000 else "1-10m" if 1000000<x<10000000 else ...)

我查看了几篇关于 lambda 函数中的多个 if 的帖子,here is an example link,但由于某种原因,该合成器在多个 if 语句中对我不起作用,但它在单个 if 条件下工作。

所以我尝试了这个“非常优雅”的解决方案:

df['Classification']=df['Size'].apply(lambda x: "<1m" if x<1000000 else pass)
df['Classification']=df['Size'].apply(lambda x: "1-10m" if 1000000 < x < 10000000 else pass)
df['Classification']=df['Size'].apply(lambda x: "10-50m" if 10000000 < x < 50000000 else pass)
df['Classification']=df['Size'].apply(lambda x: "50-100m" if 50000000 < x < 100000000 else pass)
df['Classification']=df['Size'].apply(lambda x: "100-500m" if 100000000 < x < 500000000 else pass)
df['Classification']=df['Size'].apply(lambda x: "500m-1bi" if 500000000 < x < 1000000000 else pass)
df['Classification']=df['Size'].apply(lambda x: ">1bi" if 1000000000 < x else pass)

发现“通过”似乎也不适用于 lambda 函数:

df['Classification']=df['Size'].apply(lambda x: "<1m" if x<1000000 else pass)
SyntaxError: invalid syntax

对于 Pandas 的 apply 方法中的 lambda 函数内的多重 if 语句的正确语法有什么建议吗?多线或单线解决方案都适合我。

【问题讨论】:

你可以只使用一个函数。 这看起来像@AntonvBR? @abutremutante 编写一个函数来完成这项工作并将名称作为参数传递给应用。 你看过pd.cut或categories吗? 【参考方案1】:

下面是一个小例子,您可以在此基础上进行构建:

基本上,lambda x: x.. 是函数的简短单行代码。 apply 真正需要的是一个您可以轻松地重新创建自己的功能。

import pandas as pd

# Recreate the dataframe
data = dict(Size=[80000,8000000,800000000])
df = pd.DataFrame(data)

# Create a function that returns desired values
# You only need to check upper bound as the next elif-statement will catch the value
def func(x):
    if x < 1e6:
        return "<1m"
    elif x < 1e7:
        return "1-10m"
    elif x < 5e7:
        return "10-50m"
    else:
        return 'N/A'
    # Add elif statements....

df['Classification'] = df['Size'].apply(func)

print(df)

返回:

        Size Classification
0      80000            <1m
1    8000000          1-10m
2  800000000            N/A

【讨论】:

我尝试了列出的方法,发现创建自己的函数更加灵活和透明,可以避免一些意想不到的后果 谢谢,是的,可能是这样。但是对于纯粹的性能,应该使用 maxU 示例!【参考方案2】:

你可以使用pd.cut function:

bins = [0, 1000000, 10000000, 50000000, ...]
labels = ['<1m','1-10m','10-50m', ...]

df['Classification'] = pd.cut(df['Size'], bins=bins, labels=labels)

【讨论】:

【参考方案3】:

使用 Numpy 的 searchsorted

labels = np.array(['<1m', '1-10m', '10-50m', '>50m'])
bins = np.array([1E6, 1E7, 5E7])

# Using assign is my preference as it produces a copy of df with new column
df.assign(Classification=labels[bins.searchsorted(df['Size'].values)])

如果您想在现有数据框中生成新列

df['Classification'] = labels[bins.searchsorted(df['Size'].values)]

一些解释

来自Docs:np.searchsorted

查找应插入元素以保持顺序的索引。

找到排序数组 a 中的索引,这样,如果 v 中的相应元素插入到索引之前,则 a 的顺序将被保留。

labels 数组的长度比bins 的长度大一。因为当某物大于bins 中的最大值时,searchsorted 返回一个-1。当我们对labels 进行切片时,它会抓取最后一个标签。

【讨论】:

当然很棒+1,但真的需要在这里使用 df.assign 吗?我的观点是它的可读性较差。 @AntonvBR 我爱assign 有很多原因。首先,因为当 OP 尝试我的代码时,他们不会自动破坏他们的数据框。其次,我喜欢生成新数据帧并更好地分配名称的设计模式。也就是说,我将展示两种选择(-:【参考方案4】:

apply lambda 函数实际上在这里完成了工作,我只是想知道问题出在哪里....因为您的语法看起来不错并且可以正常工作....

df1= [80000, 8000000, 8000000000, 800000000000]
df=pd.DataFrame(df1)
df.columns=['size']
df['Classification']=df['size'].apply(lambda x: '<1m' if x<1000000  else '1-10m' if 1000000<x<10000000 else '1bi')
df

输出:

【讨论】:

以上是关于在具有多个 if 语句的 Pandas Lambda 函数中使用 Apply的主要内容,如果未能解决你的问题,请参考以下文章

使用 pandas df 的具有多个 if 的 lambda 函数

具有多个条件的 if 语句

在 IF 语句中具有多个条件的 PDO MySQL SELECT

当方法包含多个具有多个返回的 if 语句时,如何从方法中获取返回值?

VBA:具有多个操作的单行 if 语句

具有多个 if 语句的嵌套 for 循环的时间复杂度