数据准备脚本:Python Pandas OR esProc SPL?

做数据分析和人工智能运算前常常需要大量的数据准备工作,也就是把各种数据源以及各种规格的数据整理成统一的格式。因为情况非常复杂多样,很难有某种可视化工具来完成此项工作,常常需要编程才能实现。

业界有很多免费的脚本语言都适合进行数据准备工作,其中Python Pandas具有多种数据源接口和丰富的计算函数,受到众多用户的喜爱;esProc SPL作为一门较新的数据计算语言,在语法灵活性和计算能力方面也很有特色,下面对两者进行多方面的比较。本文重点比较数据的解析、清洗、计算、输出等日常任务,不涉及人工智能等后续应用或高性能计算等特殊场景。

语言特征

编程范式

Python是通用开发语言,支持多范式编程,包括完整的面向对象和面向函数,但因为大量Python用户不是专业的应用程序员,很少用到这两种现代复杂的编程范式,最常用的反而是古老简单的面向过程编程范式。

SPL专用于结构化数据计算,也支持常见的三种范式。SPL对面向对象的概念进行了大幅简化,有对象的概念,可以用点号访问属性并进行多步骤计算,但没有继承重载这些内容。SPL对函数式编程也进行了简化,其Lambda表达式甚至比SQL更加简单易用,适合非专业应用程序员。

语言整体性

Pandas不是Python的原生类库,而是基于numpy开发的第三方类库(numpy本身也是第三方类库),没有参与Python的统一设计,也无法获得Python的底层支持,导致语言的整体性不佳,基础数据类型尤其是结构化数据对象(DataFrame)的专业性不强,影响编码效率和计算效率。

SPL是原生类库,可以自底向上设计统一的语法、函数、参数、接口,以及基础数据类型尤其是结构化数据对象(序表),语言的整体性更好。

运行模式

Python是用C开发的解释型语言,SPL是用Java开发的解释型语言,两者都可以自动推断数据类型,并据此提供了灵活方便的语法。解释型语言的性能一般不如编译型,但SPL内置大量时间复杂度更低的基础运算,结构化计算的性能经常能超过编译型语言。Pandas由于语言整体性较差,其性能不如Python原生类库。

IDE

Python和SPL都有图形化的IDE,包括完整的调试功能,便利的结构化数据对象观察功能,直观的代码块/作用域缩进功能。Python采用空格/tab缩进,SPL采用类Excel的表格式缩进。

学习难度

Pandas资料丰富,入门的学习难度较低。但如果要深入开发,就必须学习完整的面向对象编程和函数式编程,难度陡然提高。

SPL刻意简化了对象的概念和函数式编程的接口,无论入门学习还是深入开发,难度都不高。但涉及到高性能计算时需要学习较多特有的算法,难度也会提高。

代码量

Pandas库函数丰富,实现简单的数据准备任务时只需单独使用自己库函数,代码量较低。但如果想实现较复杂的数据准备任务,就要大量使用Python原生类库和第三方类库,由于Pandas的语言整体性不佳,难度会陡然增加,代码量也水涨船高。

SPL库函数丰富,语言整体性好,无论简单任务还是复杂任务,代码量都不多。

数据源

数据源种类

Pandas支持多种数据源,包括:

文本数据文件,包括TAB分隔的txt、逗号分隔的csv,也可自定义其它分隔符。
固定宽度文件fwf,
各类关系型数据库,
Excel,
Json,
XML,
Restful、WebService,
html抓取,
sas,
spss,
stata,
列存格式Parquet,
列存格式ORC,
Google BigQuery,
科学数据HDF,
数据框feather,
剪贴板里的结构化数据,
私有格式pickle。

SPL支持的数据源也很多,包括:

文本数据文件,包括TAB分隔的txt、逗号分隔的csv,也可自定义其它分隔符,
固定宽度文件fwf,
各类关系型数据库,
Excel,
Json,
XML,
Restful、WebService,
html抓取,
HBase,
HDFS,
Hive,
Spark,
Elasticsearch,
MongoDB,
Kafka,
R2dbc,
FTP,
Cassandra,
DynamoDB,
influxDB,
Redis,
SAP,
剪贴板里的结构化数据,
私有格式btx、ctx。

读写数据库

用SQL查询数据库,用csv文件更新数据库。Pandas:

conn = create_engine('mysql+pymysql://root:password@localhost:3306/testdb')
df_read = pd.read_sql_query('select * from product', conn)
data = pd.read_csv("d:/Orders.csv")
data.to_sql('testdf', conn, index=False)
conn.dispose()

简单读写数据库时,Pandas代码足够优雅。

SPL:

A 1 =connect(“com.mysql.jdbc.Driver”,”jdbc:mysql://localhost:3306/testdb?user=root&password=password”) 2 =A1.query(“select * from product “) 3 =T(“d:/Orders.csv”) 4 =A1.update(A3, testdf; ORDERID) 5 =A1.close()

SPL代码也很简单,整体逻辑与Pandas类似。区别在于,SPL可以把数据源信息写在配置文件里,代码里只要简单引用数据源名,具体来说,A1可以写成:connect(“myDB”)

读写文本文件

规则文本:读取csv文件,简单计算后写入新csv。Pandas:

data = pd.read_csv("d:/Orders.csv")
data['OrderDate']=pd.to_datetime(data['OrderDate'])
result=data.groupby(data['OrderDate'].dt.year).agg({'Amount':[len,np.sum]})
result.to_csv("d:/resultP.csv")

Pandas代码很简洁,但仍有不足之处,一是不能自动解析日期时间类型;二是计算代码里大中小括号都有,既有表达式又有字符串,有明显的可优化之处,语言整体性不佳。

SPL实现相同的功能:

A 1 =T(“d:/Orders.csv”) 2 =A1.groups(year(OrderDate);count(1),sum(Amount)) 3 =file(“d:/resulS.csv”).export@t(A2)

SPL代码也很简洁,且可自动解析日期时间类型,可以只用一种括号,可以只用表达式,语言整体性极佳。

不规则的文本:每三行对应一条记录,其中第二行含三个字段(集合的成员也是集合),将该文件整理成规范的结构化数据对象。Pandas:

data = pd.read_csv("d:/threeLines.txt",header=None)
pos_seq=[i//3 for i in range(len(data))]
def runSplit(x):
    f123=x.iloc[1,0].split("\t")
    f=[x.iloc[0,0],f123[0],f123[1],f123[2],x.iloc[2,0]]
    return pd.DataFrame([f], columns=['OrderID','Client','SellerId','Amount','OrderDate'])
df=data.groupby(pos_seq).apply(runSplit)
df.reset_index(drop=True, inplace=True)         #drop the Second Index

上述解析过程大体分三步:先将文本读为单字段的DataFrame;再进行有序分组,即每三行分一组;最后循环每一组,将组内数据拼成单记录的DataFrame,循环结束时合并各条记录,形成新的DataFrame。
遇到不规则的文本时,Pandas代码明显变复杂了,体现在以下几处。制造形如[0,0,0,1,1,1,2,2,2…]的分组依据时,需要用较复杂的for循环语句,先定义循环计数i,再用i整除并取商。用apply循环各组数据时,需要定义一个处理组内数据的函数,这个函数超出了一句,因此不能用Lambda表达式来简化定义过程(连Java等编译型语言都没有这种限制)。取DataFrame data的成员时,只能用函数iloc(或loc),而取list f123的成员时,可以直接用下标,两者都是集合,但用法大相径庭,只因为DataFrame不是原生类库,语言整体性较差,无法像原生类库那样享受简洁的语法规则。DataFrame本身有索引,apply拼合多个DataFrame时,会加上第二层索引,需要手工去掉一层。

SPL:

A 1 =file(“D:\split.csv”).import@si() 2 =A1.group((#-1)\3) 3 =A2.new(~(1):OrderID, (line=~(2).split(“\t”))(1):Client,line(2):SellerId,line(3):Amount,~(3):OrderDate )

SPL的解析逻辑和Pandas一样,但代码简单多了。制造分组依据时,不用复杂的for循环语句,而是用更简单的group(…)循环函数,且无需定义循环计数,#就是默认的循环计数(~是默认的循环变量)。用new循环各组数据时,也要定义一个处理函数,但SPL支持强大且简洁的Lambda表达式,可以把多句代码直接写在new里,不必像Python那样手工定义完整的函数结构。从SPL的任何集合类型(包括序表)取成员时,都可以直接用下标,语法简洁一致。new函数最后也要拼合多条记录,但不会生成无用的新索引。SPL代码更简洁,底层原因是原生类库的语言整体性更强。

多层数据

简单查询:Json文件的上层为销售员,下层为订单,查询出符合条件的所有订单。Pandas:

JsonStr=open('D:/data.json','r').read()
JsonObj=json.loads(JsonStr)
df=pd.json_normalize(JsonObj,['Orders'])
df['OrderDate']=pd.to_datetime(df['OrderDate'])
result=df.query('Amount>1000 and Amount<2000 and contains("business")') < code></2000>

Pandas代码比较简单。要注意的是,dict、list等Python基本数据支持泛型,且与Json的object、array类型天然对应,适合表示多层Json(但不适合表达二维数据)。相反,DataFrame适合表达二维数据,但同一列的数据类型不可变,不是真正的泛型,无法表达一般的多层Json。DataFrame不擅长表达多层Json,需要用json_normalize函数将多层Json转为二维DataFrame,才能进行后续计算,这说明Pandas的语言整体性不够好。

SPL:

A 1 =file(“d:/EO.json”).read() 2 =json(A1) 3 =A2.conj(Orders) 4 =A3.select(Amount>1000 && Amount

Original: https://blog.csdn.net/weixin_45526437/article/details/126836641
Author: Bug 终结者
Title: 数据准备脚本:Python Pandas OR esProc SPL?

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/669576/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球