sql concat函数_数据分析工具篇——pandas的类SQL操作

   会写python不难,写好却需要下一番功夫,上篇文章写了for循环的简单优化方法,原本想一鼓作气,梳理一下for循环优化的高级方法,但是梳理过程中发现for循环优化需要比较多的python基础知识,如果了解不透彻很难达到优化的效果,因此,笔者想用几个短篇先介绍一下python的常用包和方法,方便后续优化使用。

这篇文章我们先来了解一下pandas包中的类SQL操作,pandas中基本涵盖了SQL和EXCEL中的数据处理功能,灵活应用的话会非常高效。

数据查询

查询过程主要是从DataFrame中提取符合条件的数据块的过程,这一过程与SQL中的SELECT语法功能相似,我们从简到繁的介绍一下:

data = pd.DataFrame([['1','2','3'],['4','5','6'],['7','8','9']], columns=['a','b','c'])

我们先建一个数据结构作为完整数据集,查询的演练将在上面的数据中完成。

查询某列数据

b36ffcdef653e0964e56ce9c3d9eb50b.gif a517263268e887afc0bd70449b2d0134.png

单列数据查询我们可以用如下代码:

print(data[['a']])print(data.loc[:, ['a']])print(data.iloc[:, 0])

有没有体会到其中的差异,前两个是在原数据集中切分了两个小数据集出来,类型依然是DataFrame,而第三个方法则将切分出的数据集转化成了Series结构。

对于多列数据查询则可以变化为如下代码:

print(data[['a', 'b']])print(data.loc[:, ['a', 'b']])print(data.iloc[:, [0, 1]])print(data.iloc[:, 0:3])

此时查询出的小数据集全是DataFrame结构,比较也可以发现,iloc的函数灵活度较高。

查询某行数据

b36ffcdef653e0964e56ce9c3d9eb50b.gif a517263268e887afc0bd70449b2d0134.png

在数据查询过程中,每行的行名往往是序列号,即为index数据,所以查询过程中往往采用loc和iloc两种方法:

print(data.iloc[1, :])print(data.loc[1, :])print(data.iloc[0:1, :])print(data.loc[0:1, :])

上面的代码中前两个返回的是Series结构,而后两个返回的是DataFrame结构,另外,有三点需要强调:

其一:第三行代码返回的是第0行的数据,即0:1等价于[0, 1),而第四行代码返回的是第0,1行代码,即0:1等价于[0,1]结构。

其二:代码中的“:”类似于between……and的功能,在loc和iloc中都可以使用,但仅支持序列号。

其三:loc函数中代表列的部分不能用序列号,iloc函数中行和列位置都可以用序列号。

结合上面的两个内容,我们可以轻松的进行数据块的切分:

print(data.iloc[0:1, 0:1])print(data.iloc[0:1, [0, 1]])print(data.loc[0:1, ['a','b']])

还记不记得我们上面的描述,我们得到的结果为:

be9cdf4f46a902bd1b7e4181134b35a5.png

你有没有意识到差异在哪里?

没看错,获取的数据量不一样,大家自己考虑一下原因吧~

条件查询

b36ffcdef653e0964e56ce9c3d9eb50b.gif a517263268e887afc0bd70449b2d0134.png

写过SQL的小伙伴了解,条件查询就是SQL中WHERE的部分, pandas如何实现where条件,我们来仔细盘一下:

第一种写法:

print(data[data['a'] >= '2'])

上面可以解读为:a列中大于等于2的数据所在行对应的整行数据。

有没有好理解一点?

我们再增加一点难度:

如果有两个查询条件呢?

print(data[(data['a'] >= '2') & (data['b'] >= '5')])print(data.loc[np.logical_and(data['a']>='1', data['b']<='2')])

这其中有三个点需要着重强调:

其一:每个单独的条件需要加一个括号(),主要用来确认每个单独条件的范围;

其二:中间需要使用&等连接符号,而不能使用“and”等语法;

其三:np的逻辑函数无法实现较多条件。

WHERE条件在python中应用非常多,所以各个包中都会涉及对应的内容,在numpy中也有对应的思路:

import numpy as npA = np.array([1, 7, 4, 9, 2, 3, 6, 0, 8, 5])B = np.where(A%2 == 0, A+1, A-1)   # 偶+1,奇-1print(B)

SQL中有一个函数为like,即为模糊查询,这一查询方式在pandas中也是具有的:

print(data[data.a.str.startswith('2')])print(data[data.a.str.endswith('1')])print(data[data.a.str.contains('3')])print(data[data["a"].str.contains('1') == False and data['b'].str.contains('2') == True])

我们看到函数结构发生了变化:data.a即为第a列,str为转化为字符串查询。

既然模糊查询有了,包含关系的in结构是不是也有呢?

你猜对了~

print(data[data['a'].isin(['1','2'])])

而不包含查询的写法为:

print(data[~data['a'].isin(['1','2'])])

写到这里有没有感觉到pandas的强大,几乎涵盖了SQL的函数功能。

多DataFrame拼接

b36ffcdef653e0964e56ce9c3d9eb50b.gif a517263268e887afc0bd70449b2d0134.png

多DataFrame的查询主要是解决SQL中join和concat的问题,python中主要使用merge和concat来实现对应的功能具体写法如下:

Merge的用法:merge主要是用作按行拼接,类似于SQL中的join函数。

import pandas as pddata1 = pd.DataFrame([['1','23','3'],['2','4','6'],['3','83','9']], columns=['a','b','c'])data2 = pd.DataFrame([['2','23','3'],['2','54','26'],['3','83','19']], columns=['a','b','d'])print(pd.merge(data1, data2, on=['a','b'], how= 'inner'))print(pd.merge(data1, data2, on=['a','b'], how= 'outer'))print(pd.merge(data1, data2, on=['a','b'], how= 'left'))print(pd.merge(data1, data2, on=['a','b'], how= 'right'))

从字面意思就可以清晰理解,on是关联的主键,how是关联的方式。

我们得到对应的结果为:

780e2e7bdde8b4343ebf45faa4343c12.png

结合上文有没有发现,同样的功能,python比SQL简单,这也是python的一大优势。

Merge的操作除了可以类比于SQL操作外,还可以做集合运算(交、并、差),上文中的inner、outer可以看作是交和并,差我们会在下文中描述。

注:

此处可以补充list的交集和并集。

交集:

list(set(a).intersection(set(b)))

并集:

list(set(a).union(set(b)))

补集:b中有而a中没有。

list(set(b).difference(set(a)))

有没有感觉,不管是什么数据结构,其数据处理的逻辑是一样的。

Concat用法:主要功能是拼接,由于没有主键约束,对数据结构要求较为严格,需要人为对齐字段,这一操作类似于SQL中的union操作。

print(pd.concat([data1, data2]))print(pd.concat([data1, data2], axis=1))

其对应的结果为:

cdf749fe37d5a58b6d6bfc16d084b7fc.png

由此,我们比较出concat(axis=1)与merge的区别,concat(axis=1)是直接将代码进行拼接,而merge是通过主键对数据进行关联。

上下拼接还有一个函数,即:append。

print(data1.append(data2))

这也是一种简单的拼接方法,没有主键约束。

结合上面两种思路,我们还可以实现求补集的功能:

data1 = pd.DataFrame([['1','23','3'],['2','4','6'],['3','83','9']], columns=['a','b','c'])data2 = pd.DataFrame([['1','23','3'],['2','54','26'],['3','83','19']], columns=['a','b','c'])data1 = data1.append(data2)data1 = data1.append(data2)data3 = data1.drop_duplicates(subset=['a','b','c'],keep=False)print(data3)

这一做法主要是为了解决pandas中没有补集函数的问题,代码的灵活就在于可以用现有的函数,实现新的功能。

groupby分组功能

b36ffcdef653e0964e56ce9c3d9eb50b.gif a517263268e887afc0bd70449b2d0134.png

这一功能主要是为了实现数据集的分组功能,如下图:

433ef7bd154b46889ab4d8c8b381202b.png

几种常用的用法有:

单列分组:然后按照另一列数据计算相应值:

print(data1.groupby('a')['b'].mean())

多列分组:然后按照另一列数据计算相应值:

Agg的作用即为封装对应的函数,用于分组计算。

print(data1.groupby(['a','b']).agg('mean'))

多列分组:然后按照多列分别计算相应值:

data1 = pd.DataFrame([['1','23',3, 5],['2','4',6, 6],['3','83',9, 7]], columns=['a','b','c','d'])print(data1.groupby(['a','b']).agg({'c': np.median, 'd': np.mean}))

所能对接的函数有很多,效果不同:

print(data1.groupby('a')['b'].plot(kind='kde',legend=True,figsize=(20, 5)))

仔细分析groupby函数我们发现,groupby是一个迭代器,我们可以通过遍历的方式获取到groupby之后的内容:

data3 = data1.groupby('c')['a']for group in data3:    print(group)

得到每一个分组中的内容。

rank排序功能

b36ffcdef653e0964e56ce9c3d9eb50b.gif a517263268e887afc0bd70449b2d0134.png

组内排序我们往往使用rank函数。

data1['ranks'] = data1.groupby(['a','b'])['c'].rank()print(data1)

而全部数据的排序我们使用sort_values函数。

data2 = data2.sort_values(by=['a','b'], ascending=[True, True])print(data2)

写到这里,有没有感觉python在这块功能上完美的实现了SQL的功能?

不要着急,更完整的还在后面~

欢迎大家关注公众号: 45c42b4560f45753114dbd75e8c3ee8c.png来都来了,点个关注再走呗~
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值