化于无形的 lambda 语法

针对数据集合的每个成员进行计算是很常见的任务,用循环语句当然能实现,但比较麻烦,算个简单的求和都要写很多句代码。

编程语言经常把这些运算封装成函数,比如 Python 的 sum 函数,求订单价格总和是这样写的:

total_price = orders['price'].sum()

SQL 也可以写成:

select sum(price) total_price from orders

SPL 当然也没问题:

total_price = orders.sum(price)

看起来都很简洁。

任务当然不会总是这么简单,看一个更复杂的例子:对员工计算标签列,薪酬在 5000 以上的经理标签为 yes,其他员工为 no。

这个计算可以用一个不太复杂的表达式来描述,但不能在循环外部事先计算出结果,而要在循环中针对每个集合成员计算。这时候,可以把这个表达式定义成函数,再把这个函数作为参数传递给循环计算的函数,Python 可以这么写:

def calc_flag(row):
return 'yes' if row['position'] == 'manager' and row['salary'] > 5000 else 'no'employee['flag']=employee.apply(calc_flag, axis=1)

这段代码先定义了一个函数 calc_flag,对传入的记录 row 计算表达式。

apply 函数以 calc_flag 为参数,在循环中将集合的当前成员(记录)传递给 calc_flag 计算,并用结果组成新序列。

显然,每次都预先定义成一个函数实在是麻烦,特别是对这么一个简单表达式就能搞定的任务。于是业界发明了 lambda 语法,可以在参数中定义函数,代码简洁很多:

employee['flag'] = employee.apply(lambda row: 'yes' if row['position'] == 'manager' and row['salary'] > 5000 else 'no', axis=1)

apply 函数的参数中用 lambda 关键字定义了一个匿名函数,传入参数是记录 row。在循环过程中,apply 函数将每个成员(记录)传给 lambda 函数,计算得到新的序列。

Python 的这种写法是显式的 lambda 语法,有 lambda 关键字,要定义参数,还要写函数体。

SQL 又是如何处理这种问题的呢?

SELECT *,CASE WHEN position = 'manager' AND salary > 5000 THEN 'yes' ELSE 'no' END AS flag
FROM employee;

没有 lambda,似乎更简单了。

其实,CASE WHEN 表达式还是相当于定义了一个函数。这还是把表达式定义的函数当成循环运算的参数,本质上仍是 lambda 语法。只是 SQL 更简洁,已经看不出 lambda 语法的形式了。

SQL 专业面向结构化数据计算,仅支持二维数据表这一种集合,lambda 函数传入参数只能是记录。SQL 就不需要像 Python 那样显式定义一个 row 参数,而可以直接访问字段,这会更便捷。大多数情况下,lambda 函数中可以直接使用字段名,只有存在同名字段时才需要冠以表名(或表别名)以示区分。这样,表名和记录参数都省了,SQL 就把 lambda 函数写成了简单表达式,将 lambda 语法化于无形了。

esProc SPL 继承了 SQL 这些优点,同样把 lambda 化于无形:

employee.derive(if(position == "manager" && salary > 5000, "yes","no"))

数据集合并不只有数据表这一种。SQL 不支持其他形式的集合,处理起来会麻烦了。对于单值成员组成的集合,SQL 还可以用只有一个字段的数据表来对付。比如求一组数值的平方和,SQL 这样写:

create table numbers asselect value as nfrom (select 4.3 as value union all select 2.3 union all select 6.5 union all select 44.1) t;
select sum(n*n) from numbers;

这组数值还要额外起一个字段名和表名,有点啰嗦了。

Python 支持单值组成的集合,可以用 lambda 语法写出这样的运算:

numbers=pd.Series([4.3,2.3,6.5,44.1])
result=numbers.apply(lambda x: x * x).sum()

SPL 也有单值集合:

numbers=[4.3,2.3,6.5,44.1]
numbers.sum(~*~)

这里,sum 函数对集合循环计算的时候,将当前成员 ~ 传递给 lambda 函数求平方,再由 sum 函数求和。~ 就相当于前面 Python 代码中的 x。

在循环中,lambda 函数几乎总是用到集合的当前成员,SPL 把这个参数固化为 ~ 符号,这样就省去了参数的定义,从而把 lambda 写成简单表达式,继续保持将 lambda 化于无形的优点。

不过,对于这种相对简单的情况,Python 更提倡对位集合运算,可以避免使用 lambda 语法:

numbers=pd.Series([4.3,2.3,6.5,44.1])
result = (numbers * numbers).sum()

这显得更简洁。

前面那个员工标签的例子也可以写出来:

employee['flag'] = np.where((employee['position'] == 'manager') & (employee['salary'] > 5000), 'yes', 'no')

当表达式较复杂的时候,看着就不如 lamdba 语法简洁了。而且这种写法只适用于针对数组做过优化的运算 (比如加减乘除和这里的 if),大部分数学函数都没有做过这种优化,碰到也只能写成 lambda 语法。

说句题外话,这种写法要用 where 函数,逻辑运算符是 &,而前面 lambda 语法中是用 if 函数和 and,Python 语法经常会表现出这种不一致。lambda 语法也有这种不一致问题,在 apply 函数中能用,但 sort_values 中就不能用,这些都会加大学习难度。

SPL 也支持对位集合运算的书写形式:

(numbers ** numbers).sum()

看起来和 Python 差不多,但不如化于无形的 lambda 语法简单了。

SPL 还支持集合的集合。实际上,只要是集合,SPL 就都可以使用化于无形的 lambda 语法。比如求员工超过 10 个的部门有哪些员工:

employee.group(department).select(~.len()>10)

group 函数按部门分组后得到一个大集合,其成员是同一部门员工组成的子集合。表达式 ~.len()>10 是一个 lambda 函数,其中的 ~ 是集合的当前成员,也就是分组子集。

select 函数对大集合循环计算时,将当前成员(子集)传递给 lambda 函数,判断子集长度是否大于 10,再由 select 函数保留或舍弃这个子集。这是很自然的解题思路。

Python 一定程度也可以表示集合的集合,可以写出类似代码:

result=employee.groupby('department').filter(lambda x: len(x) >10)

对于集合的集合,就不能再使用对位运算了,采用 lambda 语法是 Python 最简单的写法,换其它方法,思路和代码都会变得更复杂。

SQL 不能描述集合的集合,对于这个问题要换种思路去实现(麻烦很多),lamdba 语法对这个问题已经无能为力了。

SPL 不仅仅是针对结构化数据计算的,但由于结构化数据过于常见,SPL 和 SQL 一样专门做了语法简化。再看一下前面计算员工标签列的例子,其实 SPL 引用字段的完整写法应该是 ~.position、~.salary,而 SPL 也提供了直接访问字段的便捷机制,就能把 lambda 函数写的和 SQL 一样简洁:

if(position == "manager" && salary > 5000, "yes","no")

Python 没做这种简化,只能写成下面这样,会导致这种最常见的情况写起来比较啰嗦。

lambda row: 'yes' if row['position'] == 'manager' and row['salary'] > 5000 else 'no'

除了当前成员之外,针对有序集合的循环计算经常还会用到成员的序号。比如:要取出一组数值中,第偶数个成员。简单思路是循环计算这个集合,如果成员的序号能被 2 整除就保留,否则就舍弃。

Python 只能给 lambda 函数传入当前成员这一个参数,必须改造这个集合,给每个成员附加上序号,才能实现这个思路:

result = filter(lambda x: x[0] % 2 == 1, enumerate(number))
even_index_members = [x[1] for x in result]

enumerate 函数将 number 的每个成员都变成数组,数组的第 0 个成员是序号,第 1 个成员是原来的数值。这样,lambda 函数才能用 x[0] 取得成员序号。过滤后还要把原来的数值拆出来,这个过程很绕,代码也繁琐。

SQL 基于无序集合,成员序号没有意义,这个问题又得绕路实现。

SPL 用 #表示当前成员的序号,用上述简单思路写出的代码非常简洁:

number.select(# % 2 ==0)

#和 ~ 一样,也是 SPL 循环函数中 lambda 函数的传入参数。

小结一下:

SQL 把二维数据表运算的 lambda 语法化于无形,用于描述常规结构化数据集合运算还是比较方便简捷的,但不能支持结构化数据以外的集合。Python 支持各种形式的集合,但 lambda 函数代码写起来也有些啰嗦,适应面不全面,语法风格也不太一致。SPL 继承了 SQL 的所有优势,且对各种形式的集合都可以使用化于无形的 lambda 语法,引入了 ~、# 等符号,进一步简化代码,而且适应面广且风格统一,是三者中最强的。

SPL是开源免费的,欢迎下载试用~~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/88428.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/88428.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

day42

1. 回调函数:把一个函数当成“任务清单”交给另一个函数,等后者干完活,就按清单执行这个函数。比如点外卖后留电话,骑手送到了就打电话(执行回调)通知你。 2. lambda函数:临时写的超短函数&…

百度日志中台前端重构实践

日志中台是百度内部针对打点数据的全生命周期管理平台,作为公司日志数据的唯一入口,承担以下核心职能:1.功能覆盖:提供从数据采集、传输、存储到查询分析的一站式服务,支持产品运营分析、研发性能监控、运维管理等多元…

資訊安全 (Information Security)3大 “CIA“要素

資訊安全之3大要素,業界慣用"CIA"稱之,包括機密性 (Confidentiality)、完整性(Integrity)與可用性(Availability);更應增加諸如鑑別性、可歸責性、不可否認性與可靠性。 1.機密性 (Confidentiality) 機密性是指採用適當的安全機制…

php后台增加权限控制

背景 最近在对接某大厂,部署差不多了,但是在漏洞扫描环节有问题,前端是用vue代码写的。后端是php。发现前端路由可以拦截未登录的url。但是后端php接口不用登录就能访问,很危险 解决方法 一、创建 Auth 中间件 首先创建一个专门…

跨平台后端编程ASP.NET CORE Razor新一代Web开发框架C#

asp.net core Razor动态语言编程代替asp.net .aspx更高级吗? https://blog.csdn.net/xiaoyao961/article/details/148846065 C#Blazor应用-跨平台WEB开发VB.NET-CSDN博客 https://blog.csdn.net/xiaoyao961/article/details/148846437 Products.razor文件,Blazor和…

Storm-Pulse 全国强对流预报接口深度解析:从技术原理到防灾应用(附API接入示例)

2025年6月14日安徽省气象台发布的强对流黄色预警中,合肥、阜阳等地出现了小时雨量 30-50 毫米的短时强降水和8-10级雷暴大风,局地甚至观测到云闪现象。强对流天气是指由强烈上升气流引发的突发性、高破坏力天气现象,涵盖了短时强降水、雷暴大…

2024中国科学技术大学计算机保研上机真题

中国科学技术大学计算机保研上机真题 在线测评链接:https://pgcode.cn/problem 运动会比赛日程安排 题目描述 某运动会设立 M M M 个比赛项目,每个运动员(共 N N N 个运动员)可以参加多个项目,每个项目的比赛时长…

(LeetCode 面试经典 150 题) 122. 买卖股票的最佳时机 II (贪心)

题目&#xff1a;122. 买卖股票的最佳时机 II 思路&#xff1a;贪心&#xff0c;时间复杂度0(n)。 当天比前一天值大&#xff0c;就进行卖出的交易。购入是默认前一天已购入。 C版本&#xff1a; class Solution { public:int maxProfit(vector<int>& prices) {int…

一篇文章了解XML

一、什么是 XML&#xff1f; XML 是一种结构化数据的标记语言&#xff0c;用来存储、传输和描述数据。 它和 HTML 很像&#xff0c;但它的标签是自定义的&#xff0c;不限定格式和外观&#xff0c;而是强调数据的结构和含义。 XML不是用来展示数据的&#xff0c;HTML是用来展…

react经验:i18n配置换行的富文本

应用场景 调用"useTranslations().rich"输出换行的文本。 实施步骤 1.翻译文件 例如:zh.json {"home":"第一行<br></br>第二行<font>加粗文本</font>" }2.调用rich处理标签 t.rich(home, { br: () > <br /&g…

Wpf中控件作为Binding的源

1、Xaml代码 Slider 滑动控件&#xff0c;设置了最小值0和最大值100&#xff0c;TextBox作为Binding的目标对象&#xff0c;它的Text属性作为Binding目标的属性&#xff0c;Binding的源的Source就是slider_test这个Slider滑动控件&#xff0c;Binding的源的Path就是slider_test…

【机器学习深度学习】典型的模型训练过程

目录 一、模型训练直观图 二、核心目标 三、训练过程详解 3.1 训练阶段 1、准备起点&#xff1a;输入数据 初始参数权重 2、模型尝试预测&#xff1a;变换计算 (前向传播) 3、检查错误&#xff1a;计算损失值 4、学习的关键&#xff1a;反向传播 梯度下降法 (调整权…

Mysql8.0版本未卸载干净如何重新下载

Mysql8.0版本未卸载干净如何重新下载 安装前准备 清理现有安装&#xff08;确保干净环境&#xff09; :: 停止并卸载现有MySQL服务 net stop MySQL >nul 2>&1 sc delete MySQL >nul 2>&1:: 删除旧数据目录 rd /s /q "C:\ProgramData\MySQL" &…

垃圾收集器G1ZGC详解

G1收集器(-XX:UseG1GC) G1 把堆划分为许多大小相同的 Region&#xff08;默认 1~32 MB&#xff0c;一个堆通常包含上千个 Region&#xff0c;JVM目标是不超过2048个Region(JVM源码里TARGET_REGION_NUMBER 定义)&#xff09; 不再是传统的 Eden、Survivor、Old 静态分代模型&…

Bootstrap 5学习教程,从入门到精通,Bootstrap 5 弹出框(Popovers) 语法知识点及案例(22)

Bootstrap 5 弹出框(Popovers) 语法知识点及案例 一、弹出框基本概念 弹出框(Popovers)是Bootstrap提供的一个小型覆盖层组件&#xff0c;用于显示额外的信息&#xff0c;当用户点击某个元素时出现&#xff0c;再次点击时消失。 二、弹出框基本语法知识点 1. 必需属性 dat…

轻巧灵动,智启未来 ——Kinova Gen3 Lite 机器人轻松解锁各行业自动化新姿势

近年来&#xff0c;Kinova Gen3 Lite 机器人凭借其卓越的性能、灵活的应用能力以及出色的性价比&#xff0c;在全球范围内掀起了一股热销狂潮。无论是科研机构、高校实验室&#xff0c;还是工业制造企业&#xff0c;都对它青睐有加。其销量持续攀升&#xff0c;市场占有率不断扩…

STM32 实现PID

&#x1f9f1; 一、PID核心模块&#xff08;模块化设计&#xff09; 头文件 pid_controller.h #pragma once #include <stdint.h>typedef struct {// 可调参数float Kp, Ki, Kd; // PID系数float output_min; // 输出下限float output_max; // 输出上…

基于MATLAB的BP神经网络回归模型在空气质量预测中的应用

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档&#xff09;&#xff0c;如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 随着城市化进程的加快和工业化的不断发展&#xff0c;空气质量问题日益受到广泛关注。空气中污染物如PM2.5、PM10、…

Linux docker拉取镜像报错解决

1、错误提示&#xff1a; Error response from daemon: Get "https://registry-1.docker.io/v2/": net/http: request canceled while waiting for connection 主要原因就是docker源不正确&#xff0c;需要配置一下。 2、报错如下&#xff1a; 3、解决办法&#x…

stm32week17+18+19+20

stm32学习 十二.串口 5.USART的HAL库用法 USART/UART异步通信配置步骤&#xff1a; 配置串口工作参数&#xff1a;HAL_UART_Init();串口底层初始化&#xff1a;HAL_UART_MspInit();开启串口异步接收中断&#xff1a;HAL_UART_Receive_IT();设置优先级&#xff0c;使能中断&…