Pandas数据分析 vs SQL统计实践

1. 目的:SQL语句的Pandas实现

数据分析师最基础的技能之一:写SQL统计数据;
然..不够使,又须多一个能力,
数据分析师最基础的技能之一:Pandas数据处理

2. 环境

  • python2.7
  • python须安装ipython, pandas, numpy, mysqldb
  • mysql, 并下载练习包employees database
    如果不想花时间搭建环境, 我已经在云端搭建了数据学习环境,按照下面的文章最后的说明,申请远程访问权限:
    2019年,数据民工的大白话规划

2.1 练习环境

  • ipython
import MySQLdb
import pandas as pd
conn = MySQLdb.connect(host='127.0.0.1', user='usertest', passwd='usertest',port=3306, db='employees', charset="utf8")
cur = conn.cursor()
df_employees = pd.read_sql('select * from employees', con=conn)
  • 备注:

python MySQLdb连接数据库,为防止查询结果中文乱码,connect参数注意增加charset="utf8"(因为一般表创建字符charset为utf8)

3. SQL实例

下面开始一步一步对照SQL的统计语句和Pandas实现方法:

3.1 单表查询

3.1.1 查询前几行

  • sql
select * from emloyees limit 10
  • pandas
# 方法一:
df_employees.iloc[0:10]
# 方法二:
df_employees.head(10)

3.1.2 查询某个字段

  • sql
select emp_no, birth_date from emloyees
  • pandas
df_employees[['emp_no', 'birth_date']]

3.1.3 查询某字段前几行

  • sql
select emp_no, birth_date from emloyees limit 10
  • pandas
df_employees[['emp_no', 'birth_date']].iloc[0:10]
df_employees[['emp_no', 'birth_date']].head(10)

3.1.4 单字段筛选特殊值

  • sql
select * from emloyees where hire_date='1986-06-26'
select * from emloyees where hire_date <> '1986-06-26'
  • pandas
df_employees.loc[df_employees['hire_date'].astype(str)=='1986-06-26']
df_employees.loc[df_employees['hire_date'].astype(str) != '1986-06-26']
df_employees.loc[df_employees['hire_date'].astype(str) <> '1986-06-26']

3.1.5 and 和 or

  • sql
select * from employees where hire_date='1986-06-26' and gender='F'
select * from employees where hire_date='1986-06-26' or gender='F'
  • pandas 方法一
df_employees.loc[(df_employees['hire_date'].astype(str)=='1986-06-26') & (df_employees['gender'].astype(str)=='M')]
df_employees.loc[(df_employees['hire_date'].astype(str)=='1986-06-26') | (df_employees['gender'].astype(str)=='M')]
  • pandas 方法二
df1 = df_employees.loc[df_employees['hire_date'].astype(str)=='1986-06-26']
df2 = df1.loc[df1['gender'].astype(str)=='F']
print df2

3.1.6 is null 和 is not null

  • sql
select * from employees where first_name is null 
  • pandas
# 当然数据可能没有空值,所以结果为空
df_employees[df_employees['first_name'].isnull()]
df_employees[df_employees['first_name'].notnull()].head(10)

3.1.6 in操作

  • sql
select * from employees where first_name in ('Parto', 'Anneke', 'Saniya')
  • pandas
df_employees.loc[df_employees['first_name'].isin(['Parto', 'Anneke', 'Saniya'])]

3.1.7 not in操作

  • sql
select * from employees where first_name not in ('Parto', 'Anneke', 'Saniya')
  • pandas
df_employees.loc[~df_employees['first_name'].isin(['Parto', 'Anneke', 'Saniya'])]
# 希望通过某列转化的list作为in的输出参数
df_employees.loc[~df_employees['first_name'].isin(df.colexample.tolist())]

3.1.8 聚合操作:count()

  • sql
select first_name, count(*) as tt from employees group by first_name order by tt
  • pandas
df_employees.groupby('first_name').size()
# 注意比较size()与count()的区别,count()把每个字段都汇总,所以用size()即可
df_employees.groupby('first_name').count()

3.1.9 order by

  • sql
select emp_no from employees order by emp_no desc
  • pandas
df_employees.sort_values(by='emp_no', ascending=False)

3.1.10 聚合操作:count()和count(distinct)

  • sql
select first_name, count(*) as tt from employees group by first_name order by tt
select gender,count(DISTINCT first_name) from employees group by gender
  • pandas
df_employees.groupby('gender').count().sort_values('first_name', ascending=False)
df_employees.groupby('gender').first_name.nunique()

3.1.11 聚合操作:sum()

  • sql
select gender, sum(emp_no) as tt from employees group by gender order by tt
  • pandas
df_employees.[['emp_no', 'gender']].groupby('gender').sum()
# pandas对非int字段,不会进行sum操作,如下结果与上面代码运行结果一样:
df_employees.groupby('gender').sum() 

3.1.12 多种聚合操作:count()与sum()

  • sql
select gender, sum(emp_no) as tt1, count(*) as tt2 from employees group by gender order by tt1 desc
select gender,first_name, sum(emp_no) as tt1, count(*) as tt2 
from employees group by gender,first_name
  • pandas
df_employees.groupby('gender').agg({'emp_no':np.sum, 'first_name':np.size}).sort_values(by='emp_no', ascending=False)
df_employees.groupby(['gender','first_name']).agg({'emp_no':[np.sum, np.size]})

3.1.13 待更新

3.2 单表查询

3.2.1 连接:Left join,Rigth join,Full join

  • 新读入薪水表
df_salaries = pd.read_sql('select * from salaries', con=conn)
  • sql
select * from employees t1 left join salaries t2 on t1.emp_no=t2.emp_no
select * from employees t1 right join salaries t2 on t1.emp_no=t2.emp_no
select * from employees t1 full join salaries t2 on t1.emp_no=t2.emp_no
  • pandas
pd.merge(df_employees, df_salaries , on='emp_no', how='left')
pd.merge(df_employees, df_salaries , on='emp_no', how='right')
pd.merge(df_employees, df_salaries , on='emp_no', how='outer')
# 如果是多列作为连接条件:
pd.merge(df_employees, df_salaries , left_on=['emp_no', 'hire_date'], right_on=['emp_no', 'to_date'], how='inner')
  • join 函数
# 如果两个dataframe待连接字段名字不同
# 如下: 通过df_employees的columnName 与 df_salaries的newColumn进行连接
df_employees.set_index('columnName').join(df_salaries.set_index('newColumn'))

df_employees.join(df_salaries.set_index("birth_date"), on='hire_date', lsuffix='_one', rsuffix='_another', how='left')

3.2.2 union all

  • sql
(select * from employees t1 limit 10)
union all 
(select * from employees t1 limit 20,10)
  • pandas
pd.concat([df_employees.iloc[0:10], df_employees.iloc[10:21]])

3.2.2 union all 和 union

  • sql
(select * from employees t1 limit 10)
union all 
(select * from employees t1 limit 20,10)
  • pandas
pd.concat([df_employees.iloc[0:10], df_employees.iloc[10:21]])
pd.concat([df_employees.iloc[0:10], df_employees.iloc[10:21]])

3.2.3 row_number()

  • sql
# mysql没有row_number()功能,oracle有, 如下模拟oracle写法(实际mysql无法运行哈,意会下精神,咳咳)
SELECT * FROM 
( SELECT t.*, ROW_NUMBER() OVER(PARTITION BY gender ORDER BY emp_no DESC) AS rn FROM employees t)
WHERE rn < 5
ORDER BY gender ,rn;
  • pandas
(df_employees.assign(rn=df_employees.sort_values(['emp_no'], ascending=False).groupby(['gender']).cumcount()+1).query('rn<5').sort_values(['gender','rn']))

3.2.4 update

  • sql
update employees
set emp_no=100
where emp_no=10001
  • pandas
df_employees.loc[df_employees['emp_no']==10001, 'emp_no'] = 99

3.2.5 delete

  • sql
delete employees
where emp_no=10003
  • pandas
df1 = df_employees.loc[df_employees['emp_no'] != 10003]

待更新..

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 224,764评论 6 522
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 96,235评论 3 402
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 171,965评论 0 366
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 60,984评论 1 300
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 69,984评论 6 399
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 53,471评论 1 314
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 41,844评论 3 428
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 40,818评论 0 279
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 47,359评论 1 324
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 39,385评论 3 346
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 41,515评论 1 354
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 37,114评论 5 350
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 42,836评论 3 338
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 33,291评论 0 25
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 34,422评论 1 275
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 50,064评论 3 381
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 46,581评论 2 365

推荐阅读更多精彩内容