Python数据分析之路(一)查询和统计

0. 如何入门数据分析

关注沙漠之鹰的同学一定看过沙漠君写得很多篇数据分析文章,比如分析房价,车价,预测机动车摇号这些话题。其实文章中所有的分析都使用了Python和它非常强大的数据分析库Pandas。一些机器学习和预测的功能则用到了sklearn库。掌握了这些工具,就能应对绝大多数的分析需求。

纸上得来终觉浅,即使你看了很多书和代码,也未必比得上多接触例子多敲一些代码,三四个中等规模(约一两百行代码的)的案例就能让你有整体的把握。至于数据采集,沙漠之鹰有开源的数据抓取工具Hawk,网上也有众多如何获取数据的教程,因此本文不再详述。

系列文章分为三个部分:

*
1. 查询与统计
*
1. 可视化和高级用法
*
1. 分类和预测(估计会分为几篇文章)

好了,废话不多说,进入正题。

1. 找到好的问题

好的问题其实比答案更重要。人认识问题,分为四种级别:

  1. 我们知道自己知道的(房价在涨)
  2. 知道自己不知道的(可度量的信息,如房价平均涨幅)
  3. 不知道自己知道的(如证明摇号系统漏洞)
  4. 不知道自己不知道的(最有价值,蕴含着最大的机会)

沙漠君期待于寻找3-4层级的问题,可是多数情况只能在第1和第2档上徘徊。当你发现一个问题之后,还需要思考3个问题:

  • 我是否找到了一个值得解决的问题?
  • 我是否提出了一个足够好的解决方案
  • 我真的想去解决这个问题吗?

最后的动力往往反映了你能解决问题的最大限度,很多人可能只是完成了任务,所以有了一点成功,他们就停滞不前,错过了最大的金矿。数据的质量比数量更重要,如果你不知道什么样的数据更重要,即使拥有更多的数据也只会导致呕吐。数据分析需要有重点,需要从众多图表和信息中找到问题的核心。

[En]

The final motivation often reflects the maximum limit to which you can solve the problem, and many people may just complete the task, so with a little success, they stagnate and miss the biggest gold mine. The quality of the data is more important than the quantity, and if you don’t know what kind of data is more important, even having more data will only cause vomiting. Data analysis requires focus and needs to find the core of the problem from numerous charts and information.

一般来说,人们对变化的指标更感兴趣,所以比率和增长率比静态数据更有说服力。变化分为长期和短期,从不同维度得出的结论往往完全不同。相关性较好,因果关系较好。有了因果关系,你就有能力改变未来。

[En]

Generally speaking, people are more interested in changing indicators, so ratios and growth rates are more persuasive than static data. The change is divided into long-term and short-term, and the conclusions drawn from different dimensions are often completely different. The correlation is good, and the causality is better. With causality, you have the ability to change the future.

下图展示了数据分析的一般流程(图片来自网络):

Python数据分析之路(一)查询和统计

统计的三大核心:分组(map),聚合(reduce),排序(sort)。它们用的是如此普遍,因此MapReduce管道框架成了数据分析的标准,也非常适合做多机并行化。分组和排序很好理解,聚合指的是对各组内容做求和,分组等。

绝大部分数据分析操作,都可以通过查询,分组,聚合,排序四个元素进行级联组合进行。因此掌握这四大天王,应付一般的场景就都无问题了。 (这应该是这篇文章最重要的一句话了)

2. 查询和过滤

DataFrame是pandas的核心数据结构,可以理解为Excel里的二维矩阵,它更高级,能表达3维或更高维的数据,支持多索引。在内存中存取,效率极高,绝大多数操作都和DataFrame相关。维度为2的DataFrame,行(column)和列(row)的axis分别为0和1。可以针对某些列做索引(index),高维DataFrame是相当少见的。

2.1 查询

下面的表展示了Pandas对索引的介绍:

符号 说明 例子 [] 列值索引 df[‘房价’] ,df[[‘房价’,’车价’]] loc 行值索引 df.loc[0], df[‘2013′:’2015’] iloc 行号索引 df.iloc[0], df.iloc[2:10] ix 行索引 df.ix[0], df.ix[2:10]

时间也是比较重要的index,比较好用的是Timestamp,接受 2016-12-24这种字符串,字符串到时间转换代码如下:

weather.index= weather[u'日期'].map(lambda x:Timestamp(x))

Pandas的索引功能非常强大,补充如下:

*
1. loc也能支持先行后列的查询: df.loc['20130101':'20130103' , ['A','B']],类似的如 iloc
*
1. 个人感觉ix的有些冗余,和 ixiloc类似

所有索引都支持字符串和数组,以及切片(slice)用于指定范围,索引还能传递一个bool类型的lambda表达式,或返回和其shape一致的bool数组
这种用法可以用在过滤上,这非常重要,我们再给几个例子:

2.2 过滤

过滤有两方面需求:找出特定数据进行针对性分析,或

  • 针对特定数据做分析,
  • 过滤异常值。

异常值非常重要,应仔细分析其原因。如果真的是异常值,就应该提前进行过滤,否则聚合会严重影响结果,比如房价天价。

[En]

Abnormal values are very important, and the causes of them should be carefully analyzed. If they are really outliers, they should be filtered in advance, otherwise the aggregation will seriously affect the results, such as sky-high house prices.

先讨论按行过滤:非空过滤,过滤掉 col列为空的内容:

df=df[!data.col.isnull()]

字符串过滤:

db[db.city.str.contains(u'市')]

若需要对df对某个键去重:

qq['id'].unique()

isin能判断单元格中的值是否在给定的数组内,若希望对多个列做过滤,Pandas提供了现成的方法df.filter,还支持正则。还能进行逻辑操作,实现更复杂的需求。

2.3 遍历

当您有索引和列操作时,为什么需要遍历?因为遍历更加灵活,当然,性能相对较差:

[En]

Why do you need traversal when you have indexes and column operations? Because traversal is more flexible, of course, the performance is relatively poor:

函数 遍历目标 lambda参数 说明 map 一列的cell cell 最为常见 apply 列/行 列或行的Series axis:不填写cell,1:行,2:列 applymap cell cell element-wise最为灵活 iterrows 行遍历 提供行号 见备注 iteritems 列遍历 提供列名 见备注 itertuples 行遍历 提供index 见备注

map, apply,applymap是只返回单元格或行列本身的,参数都是lambda,本节假设读者对python的lambda表达式有足够的了解。

但这样不能实现如”奇数偶数行做分别作不同处理的需求,则这三个函数就无能为力。因此就有后面iterrows等三个函数。如iterrows,它会将行号和行迭代出来,从而方便自定义逻辑,示例如下:

for i,row in data.iterrows():
    pass

2.4 求值和合并

一张表可能很难包含所有的信息,因此需要计算新值(求值)或join其他表(合并),但Pandas本身的Join并不好用,经常出错。

如果某个属性可以通过计算获得,可对各个列当做变量来处理,由于内部使用了C++和numpy加速,效率远比for循环更高,下面是处理房价的一个例子: 总价/单价,并做小数点截取:

table['面积']= np.round(table['总价']*10000/table['单价'])

numpy提供了绝大多数常见的函数算子,能满足大部分需求。下面是合并:

  • 横向合并(需保证行数一致)- 横向合并 df = pd.concat([data_train, dummies_Cabin])
  • 删除列 df.drop(['Pclass', 'Name', 'Sex')]
  • 纵向合并(join操作)
data.merge(right=prop_rates, how='inner',left_on='Property_Area',right_index=True, sort=False)

如果不加参数,则可以自动通过列名合并。join的参数比较复杂,建议直接参考Pandas官方文档。

3. 分组,排序,聚合

排序、分组和聚合的组合有无数种,这在技术层面上并不困难。但如果你想写一份报告,要避免大而全面,因为客户的注意力很容易被浪费在毫无意义的图表上。了解客户真正关心的是什么,行业背景分析,用户画像,竞争产品监控,销售行为分析。如果你正在写一篇受欢迎的文章,多问几个人你想知道什么。

[En]

There are countless combinations of sorting, grouping, and aggregation, which is not difficult at the technical level. But if you want to write a report, avoid being big and comprehensive, because the customer’s attention can easily be wasted on meaningless charts. Get out what customers really care about, industry background analysis, user portraits, competitive product monitoring, sales behavior analysis. If you are writing a popular article, ask a few more people what you want to know.

由于分组是基础,我们先介绍分组:

3.1 分组

分组就是按照一个或多个键,将数据分为几个组的过程。你可以直接传列名做分组, df.groupby('column_name')

也可以传递相同行数的Series甚至DataFrame。下面的例子是按日期里的年做分组:

df2.groupby(df2.日期.map(lambda x:x.year))

Pandas也能支持传递多个列的数组,除了切片以外,能在索引上使用的基本都能在group,sort上使用,一致性的API上手非常容易。

值得注意的是,由于时间索引分组比较困难,例如每五个月一组,可以用针对TimeStamp特定优化的方案,如resample:

下面计算了北京按年平均的AQI:

db[db.city==u'北京'][u'平均值'].resample('12M').aqi.mean()

3.2 排序

Pandas的排序非常之快,大部分操作都能在瞬间完成。排序分为两类:

对一般数据排序

一般排序,直接用 sort即可,传递lambda,列名或多个列,或长度一致的Series,这与groupby等其他API一致,此处从略。

可指定 ascending=True|False来指定升序,降序。

对分组后数据排序

groupby之后的数据,和一般的DataFrame不同,而像个字典(dict)。对键排序,需使用sort_index,值排序,需使用sort_values。

3.3 聚合

聚合可将分组后的数据按需求重新打平。如求每个分组的最大值(max),最小值(min),或数量等,例如:

df2.groupby(df2.日期.map(lambda x:x.year)).size()

我们来写几个例子大家说说是什么意思:

car.groupby(car.年月.map(lambda x:x.month)).销量.sum().plot(kind='bar',title='汽车市场月度销量汇总')

将汽车数据按照月份分组,按销量求和。然后绘制直方图:

Python数据分析之路(一)查询和统计

Pandas支持直接将聚合结果绘图输出(虽然丑但是方便啊),下一节我们将详细介绍它的使用细节。

这条语句统计了广西省东风MPV的各车型总体销量情况,并按数量降序:

df[(df.省=='广西') & (df.车型分类=='MPV') & (df.品牌=='东风')].groupby('车型').size().sort_values(ascending=False)

3.4 数据透视表

如果我想一次性地针对多种分组方式实行多种聚合策略,有没有更方便的API? 答案是数据透视表(pivot_table)。Excel也有该功能,异常强大,有了它,一般需求几乎都能实现。

有篇文章讲的非常详细,此处就不班门弄斧了,参考:

http://python.jobbole.com/81212/

下面是同时按 Name rep manager分组,按价格分别以总价和数量聚合,并将空值填为0.

pd.pivot_table(df,index=["Name","Rep","Manager"],values=["Price"],aggfunc=[np.sum,len],fill_value=0)

Python数据分析之路(一)查询和统计

pivot之后,生成的DataFrame是multiindex的,处理起来稍显繁琐,用xs可将某个子index的数据”提升”出来,例如:

df_pivot.xs(('12AM新坐标',2011))

至于更复杂的访问和采样,可配合loc和PD.IndexSlice, 可自行查看官方文档。

4. 总结

Pandas本身异常强大,功能非常繁杂,笔者仅仅掌握了其中非常小的一部分。但是对于一般的需求都能通过简单的操作组合出来。API的一致性非常重要,Pandas(包括numpy等)都继承了Python的优良特性,因此只要能举一反三,就能进步神速。

文章不能太长,否则就没人看得完了。不过相信我,掌握文中说的用法,基本上就足够混口饭吃了。因为写SQL的速度和灵活性是远远不及Pandas语法的。下一篇是数据可视化,我们来讨论如何做可视化,还有对应的Python库。

有任何问题,欢迎交流。

Original: https://www.cnblogs.com/buptzym/p/7144122.html
Author: FerventDesert
Title: Python数据分析之路(一)查询和统计

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

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

(0)

大家都在看

发表回复

登录后才能评论
免费咨询
免费咨询
扫码关注
扫码关注
联系站长

站长Johngo!

大数据和算法重度研究者!

持续产出大数据、算法、LeetCode干货,以及业界好资源!

2022012703491714

微信来撩,免费咨询:xiaozhu_tec

分享本页
返回顶部