0%

It’s not about where your starting point is, but your end goal and the journey that will get you there.

在P2阶段的末尾,课程中涉及到了一个新的pandas函数——merge,有些同学对merge的用法存在疑惑,尤其是查了一下Pandas如何做数据合并之后,发现除了merge之外,还有concat、还有join,还有append,更是一脸懵了,那这期导学呢,我们就来一起梳理一下pandas数据合并的知识点,同学们不要慌,除了代码之外,还嵌入了DataFrame的图片方便大家理解。当然,看完之后还是要自己多练习才行!加油!

merge

官方文档

文档链接

pandas.DataFrame.merge

常用参数解读

  • right:合并的另一个DataFrame

  • how:数据融合的方式,包括:left、right、outer和inner,默认是inner

    merge的连接方式与SQL对比

    合并方式 SQL JOIN 描述
    left LEFT OUTER JOIN 只用左表的key去匹配链接
    right RIGHT OUTER JOIN 只用右表的key去匹配链接
    outer FULL OUTER JOIN 两表中key的并集
    inner INNER JOIN 两表中key的交集
  • on:进行合并的共有列的名字,用到这个参数的时候一定要保证左表和右表的共有列都有相同的列名

  • left_on:左表对齐的列,可以是列名,也可以是和dataframe同样长度的arrays。

  • right_on:右表对齐的列,可以是列名,也可以是和dataframe同样长度的arrays。

  • left_index/ right_index: 布尔值,如果是True的话,以index作为key

  • sort:布尔值,会根据dataframe合并的keys按字典顺序(abcd…这种)排序,默认为True,设置为False可以提高运算速率。

合并方法

  • 一对一 : 联接两个 DataFrame 的key唯一

  • 多对一 : 将一个DataFrame的唯一key连接到另一个 DataFrame 中的一个或多个key

    • 多对多 : keys 对 keys

实例

  • 一对一

    默认连接方式为inner,即取交集

1
2
3
4
5
6
7
8
9
10
11
In [1]: left = pd.DataFrame({'key': ['K0', 'K1', 'K2', 'K3'],
....: 'A': ['A0', 'A1', 'A2', 'A3'],
....: 'B': ['B0', 'B1', 'B2', 'B3']})
....:

In [2]: right = pd.DataFrame({'key': ['K0', 'K1', 'K2', 'K3'],
....: 'C': ['C0', 'C1', 'C2', 'C3'],
....: 'D': ['D0', 'D1', 'D2', 'D3']})
....:

In [3]: result = pd.merge(left, right, on='key')

_images/merging_merge_on_key.png

  • 多对多(默认内链接)
1
2
3
4
5
6
7
8
9
10
11
12
13
In [4]: left = pd.DataFrame({'key1': ['K0', 'K0', 'K1', 'K2'],
....: 'key2': ['K0', 'K1', 'K0', 'K1'],
....: 'A': ['A0', 'A1', 'A2', 'A3'],
....: 'B': ['B0', 'B1', 'B2', 'B3']})
....:

In [5]: right = pd.DataFrame({'key1': ['K0', 'K1', 'K1', 'K2'],
....: 'key2': ['K0', 'K0', 'K0', 'K0'],
....: 'C': ['C0', 'C1', 'C2', 'C3'],
....: 'D': ['D0', 'D1', 'D2', 'D3']})
....:

In [6]: result = pd.merge(left, right, on=['key1', 'key2'])

_images/merging_merge_on_key_multiple.png

  • 左链接
1
In [7]: result = pd.merge(left, right, how='left', on=['key1', 'key2'])

_images/merging_merge_on_key_left.png

  • 右链接
1
In [8]: result = pd.merge(left, right, how='right', on=['key1', 'key2'])

_images/merging_merge_on_key_right.png

  • 外链接
1
In [9]: result = pd.merge(left, right, how='outer', on=['key1', 'key2'])

_images/merging_merge_on_key_outer.png

  • 利用index链接

    这里就要用到left_indexright_index参数了,实例如下:

    1
    In [10]: result = pd.merge(left, right, left_index=True, right_index=True, how='outer')

    _images/merging_merge_index_outer.png

重复列的处理

当你进行合并时,key有重复的话,会额外输出行数X重名列数的数据,不仅结果错误,还会导致电脑运行速度巨慢,所以,合并前一定要检查是否有重复列名,当然你可以直接比对两表的列名,或者选择如下方法:

1
2
3
4
5
6
7
In [10]: left = pd.DataFrame({'A' : [1,2], 'B' : [1, 2]})

In [11]: right = pd.DataFrame({'A' : [4,5,6], 'B': [2, 2, 2]})

In [12]: result = pd.merge(left, right, on='B', how='outer', validate="one_to_one")
...
MergeError: Merge keys are not unique in right dataset; not a one-to-one merge

当有重名列的时候,就会报错,那么如果想继续合并的话,只需把validate参数改为"one_to_many"

1
2
3
4
5
6
7
In [13]: pd.merge(left, right, on='B', how='outer', validate="one_to_many")
Out[13]:
A_x B A_y
0 1 1 NaN
1 2 2 4.0
2 2 2 5.0
3 2 2 6.0

如果你想在合并后,把两表中重名的列加上后缀的话,可以使用suffixes参数

1
2
3
4
5
In [27]: left = pd.DataFrame({'k': ['K0', 'K1', 'K2'], 'v': [1, 2, 3]})

In [28]: right = pd.DataFrame({'k': ['K0', 'K0', 'K3'], 'v': [4, 5, 6]})

In [29]: result = pd.merge(left, right, on='k', suffixes=['_l', '_r'])

_images/merging_merge_overlapped_suffix.png

indicator参数

在merge里,还有一个有意思的参数叫indicator,可以输入布尔值(默认为False),当你设置为True的时候,会在你合并的表中,增加一列_merge,元素则表示了合并后的数据来自左表还是右表或者二者皆有。

看示例:

1
2
3
4
5
6
7
8
9
10
11
In [14]: df1 = pd.DataFrame({'col1': [0, 1], 'col_left':['a', 'b']})

In [15]: df2 = pd.DataFrame({'col1': [1, 2, 2],'col_right':[2, 2, 2]})

In [16]: pd.merge(df1, df2, on='col1', how='outer', indicator=True)
Out[16]:
col1 col_left col_right _merge
0 0 a NaN left_only
1 1 b 2.0 both
2 2 NaN 2.0 right_only
3 2 NaN 2.0 right_only

或者也可以输入一个字符串作为列名:

1
2
3
4
5
6
7
In [17]: pd.merge(df1, df2, on='col1', how='outer', indicator='indicator_column')
Out[17]:
col1 col_left col_right indicator_column
0 0 a NaN left_only
1 1 b 2.0 both
2 2 NaN 2.0 right_only
3 2 NaN 2.0 right_only

join

官方文档

文档链接

pandas.DataFrame.join

常用参数解读

  • other : DataFrame , 或者是有列名的Series
  • on : 也就是merge的key,可以输入key或者keys,默认为index
  • how : left、right、outer、inner,默认为left

合并方法

join是一种快速合并方法,所需参数较少,默认以index作为链接键。

实例

  • 最常用
1
2
3
4
5
6
7
8
9
10
11
In [18]: left = pd.DataFrame({'A': ['A0', 'A1', 'A2'],
....: 'B': ['B0', 'B1', 'B2']},
....: index=['K0', 'K1', 'K2'])
....:

In [19]: right = pd.DataFrame({'C': ['C0', 'C2', 'C3'],
....: 'D': ['D0', 'D2', 'D3']},
....: index=['K0', 'K2', 'K3'])
....:

In [20]: result = left.join(right)

_images/merging_join.png

  • 外连接
1
In [21]: result = left.join(right, how='outer')

_images/merging_join_outer.png

  • 内连接
1
In [22]: result = left.join(right, how='inner')

_images/merging_join_inner.png

  • 键为列与index
1
2
3
4
5
6
7
8
9
10
11
In [23]: left = pd.DataFrame({'A': ['A0', 'A1', 'A2', 'A3'],
....: 'B': ['B0', 'B1', 'B2', 'B3'],
....: 'key': ['K0', 'K1', 'K0', 'K1']})
....:

In [24]: right = pd.DataFrame({'C': ['C0', 'C1'],
....: 'D': ['D0', 'D1']},
....: index=['K0', 'K1'])
....:

In [25]: result = left.join(right, on='key')

_images/merging_join_key_columns.png

  • 键为多列与多index
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
In [26]: left = pd.DataFrame({'A': ['A0', 'A1', 'A2', 'A3'],
....: 'B': ['B0', 'B1', 'B2', 'B3'],
....: 'key1': ['K0', 'K0', 'K1', 'K2'],
....: 'key2': ['K0', 'K1', 'K0', 'K1']})
....:

In [27]: index = pd.MultiIndex.from_tuples([('K0', 'K0'), ('K1', 'K0'),
....: ('K2', 'K0'), ('K2', 'K1')])
....:

In [28]: right = pd.DataFrame({'C': ['C0', 'C1', 'C2', 'C3'],
....: 'D': ['D0', 'D1', 'D2', 'D3']},
....: index=index)
....:
In [29]: result = left.join(right, on=['key1', 'key2'])

_images/merging_join_multikeys.png

  • 键为单index与多重index
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
In [30]: left = pd.DataFrame({'A': ['A0', 'A1', 'A2'],
....: 'B': ['B0', 'B1', 'B2']},
....: index=pd.Index(['K0', 'K1', 'K2'], name='key'))
....:

In [31]: index = pd.MultiIndex.from_tuples([('K0', 'Y0'), ('K1', 'Y1'),
....: ('K2', 'Y2'), ('K2', 'Y3')],
....: names=['key', 'Y'])
....:

In [32]: right = pd.DataFrame({'C': ['C0', 'C1', 'C2', 'C3'],
....: 'D': ['D0', 'D1', 'D2', 'D3']},
....: index=index)
....:

In [33]: result = left.join(right, how='inner')

_images/merging_join_multiindex_inner.png

你也可以用merge来实现:

1
2
3
In [34]: result = pd.merge(left.reset_index(), right.reset_index(),
....: on=['key'], how='inner').set_index(['key','Y'])
....:
  • 键为两个多重index

这里用join就不能实现了,但是你可以用merge,方法跟上面merge的用法类似

1
2
3
4
5
6
7
8
9
10
11
12
13
In [35]: index = pd.MultiIndex.from_tuples([('K0', 'X0'), ('K0', 'X1'),
....: ('K1', 'X2')],
....: names=['key', 'X'])
....:

In [36]: left = pd.DataFrame({'A': ['A0', 'A1', 'A2'],
.....: 'B': ['B0', 'B1', 'B2']},
.....: index=index)
.....:

In [37]: result = pd.merge(left.reset_index(), right.reset_index(),
.....: on=['key'], how='inner').set_index(['key','X','Y'])
.....:

_images/merging_merge_two_multiindex.png

重复列的处理

1
2
3
4
5
In [38]: left = pd.DataFrame({ 'v': [1, 2, 3]},index = ['K0', 'K1', 'K2'])

In [39]: right = pd.DataFrame({ 'v': [4, 5, 6]},index = ['K0', 'K0', 'K3'])

In [40]: result = left.join(right, lsuffix='_l', rsuffix='_r')

_images/merging_merge_overlapped_multi_suffix.png

多表的连接

1
2
3
In [41]: right2 = pd.DataFrame({'v': [7, 8, 9]}, index=['K1', 'K1', 'K2'])

In [42]: result = left.join([right, right2])

_images/merging_join_multi_df.png

concat

官方文档

文档链接

pandas.concat

常用参数解读

  • objs::series或者dataframe
  • axis: 需要合并连接的轴,0表示行,1表示列
  • join:inner或者outer,默认为outer

合并方法

实例

  • 纵向连接相同列名的表
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
In [1]: df1 = pd.DataFrame({'A': ['A0', 'A1', 'A2', 'A3'],
...: 'B': ['B0', 'B1', 'B2', 'B3'],
...: 'C': ['C0', 'C1', 'C2', 'C3'],
...: 'D': ['D0', 'D1', 'D2', 'D3']},
...: index=[0, 1, 2, 3])
...:

In [2]: df2 = pd.DataFrame({'A': ['A4', 'A5', 'A6', 'A7'],
...: 'B': ['B4', 'B5', 'B6', 'B7'],
...: 'C': ['C4', 'C5', 'C6', 'C7'],
...: 'D': ['D4', 'D5', 'D6', 'D7']},
...: index=[4, 5, 6, 7])
...:

In [3]: df3 = pd.DataFrame({'A': ['A8', 'A9', 'A10', 'A11'],
...: 'B': ['B8', 'B9', 'B10', 'B11'],
...: 'C': ['C8', 'C9', 'C10', 'C11'],
...: 'D': ['D8', 'D9', 'D10', 'D11']},
...: index=[8, 9, 10, 11])
...:

In [4]: frames = [df1, df2, df3]

In [5]: result = pd.concat(frames)

_images/merging_concat_basic.png

你也可以设置key参数,来区分数据来自哪张表

1
In [6]: result = pd.concat(frames, keys=['x', 'y', 'z'])

_images/merging_concat_keys.png

  • 行拼接(默认外连接)
1
2
3
4
5
6
7
In [8]: df4 = pd.DataFrame({'B': ['B2', 'B3', 'B6', 'B7'],
...: 'D': ['D2', 'D3', 'D6', 'D7'],
...: 'F': ['F2', 'F3', 'F6', 'F7']},
...: index=[2, 3, 6, 7])
...:

In [9]: result = pd.concat([df1, df4], axis=1, sort=False)

_images/merging_concat_axis1.png

  • 行拼接(设置内连接)
1
In [10]: result = pd.concat([df1, df4], axis=1, join='inner')

_images/merging_concat_axis1_inner.png

  • 行拼接(只筛选出某一表的index)
1
In [11]: result = pd.concat([df1, df4], axis=1, join_axes=[df1.index])

_images/merging_concat_axis1_join_axes.png

  • 无视index的合并

    当数据表的index没有实际意义时,可以使用ignore_index参数,来重置合并后的数据集index

1
In [15]: result = pd.concat([df1, df4], ignore_index=True)

_images/merging_concat_ignore_index.png

  • 合并DataFrame与Series
1
2
3
In [17]: s1 = pd.Series(['X0', 'X1', 'X2', 'X3'], name='X')

In [18]: result = pd.concat([df1, s1], axis=1)

_images/merging_concat_mixed_ndim.png

当然你也可以使用ignore_index参数,将列名重置

1
In [21]: result = pd.concat([df1, s1], axis=1, ignore_index=True)

_images/merging_concat_series_ignore_index.png

  • 合并若干Series
1
2
3
4
5
6
7
8
9
10
11
12
13
In [22]: s3 = pd.Series([0, 1, 2, 3], name='foo')

In [23]: s4 = pd.Series([0, 1, 2, 3])

In [24]: s5 = pd.Series([0, 1, 4, 5])

In [25]: pd.concat([s3, s4, s5], axis=1)
Out[25]:
foo 0 1
0 0 0 0
1 1 1 1
2 2 2 4
3 3 3 5

你可以添加keys参数,来给合并后的数据集添加列名

1
2
3
4
5
6
7
In [26]: pd.concat([s3, s4, s5], axis=1, keys=['red','blue','yellow'])
Out[26]:
red blue yellow
0 0 0 0
1 1 1 1
2 2 2 4
3 3 3 5

append

append其实就是concat的一个便捷函数,实现列的拼接

1
In [12]: result = df1.append(df2)

_images/merging_append1.png

  • 当两表列名不一致时
1
In [13]: result = df1.append(df4)

_images/merging_append2.png

你可以添加参数ignore_index = True,来重置合并数据集的index

1
In [16]: result = df1.append(df4, ignore_index=True)

_images/merging_append_ignore_index.png

  • 合并多个表
1
In [14]: result = df1.append([df2, df3])

_images/merging_append3.png

  • DataFrame添加Series
1
2
3
In [34]: s2 = pd.Series(['X0', 'X1', 'X2', 'X3'], index=['A', 'B', 'C', 'D'])

In [35]: result = df1.append(s2, ignore_index=True)

_images/merging_append_series_as_row.png

其他

合并两表中的值

你以后也许会在工作中遇到这种情况,你的团队中针对同一情况统计了两份数据,但是这两份数据都有一些缺失值,那么如何让他们相互“弥补”这些缺失值呢?

试试pandas.DataFrame.combine_first

1
2
3
4
5
6
7
8
In [43]: df1 = pd.DataFrame([[np.nan, 3., 5.], [-4.6, np.nan, np.nan],
.....: [np.nan, 7., np.nan]])
.....:

In [44]: df2 = pd.DataFrame([[-42.6, np.nan, -8.2], [-5., 1.6, 4]],
.....: index=[1, 2])
.....:
In [45]: result = df1.combine_first(df2)

_images/merging_combine_first.png

但是,此方法只是利用右表中的值替换了左表中的NaN。

另外,你还可以试试pandas.DataFrame.update,这次替换的不仅仅是NaN值,还有其他所有能在右表中找到的相同位置的值。

1
In [46]: df1.update(df2)

_images/merging_update.png

总结

  • merge主要用来根据key对数据集进行合并;
  • join相当于简化版的merge,key默认为index,所以你如果想按照index对数据集合并时,join就是你的首选;
  • concat其实是concatenate的简称,翻译过来是“连接”,所以,如果你想对数据集进行横向连接(axis = 1)或者纵向链接时,记得想起来用concat;
  • append相当于是简化版的concat,用得频次比concat要多得多。

希望能通过这篇导学,给大家扫除Pandas数据融合的疑惑,当然还是那句话,Learning by doing,光看不练可不行哦,打开你的Jupyter Notebook,试试看!

Build a dream and the dream will build you.

Hi,同学们,上一阶段我们学习了Python的基础知识,简单了解了Python数据分析的关键库——Pandas,并且通过项目二的实战,相信大家也一定信心满满的准备学习更多的Pandas知识了吧!那么从今天开始未来的四周内,我们将会对Pandas进行更细致的学习,大家加油吧!

本周开始,我们就进入到了项目三(P3)阶段,本阶段总共包含四周,在这一个月内,我们要对数据分析入门进行学习,学习数据分析思维,掌握Python数据分析及可视化方法,并使用所学知识完成项目三:探索数据集,尝试着自己完成整个数据分析的流程,得到一些饶有兴趣的结论,你一定会非常有成就感哒!那么以下便是这四周的学习安排:

时间 学习重点 对应课程
第1周 数据分析过程-1 数据分析过程&案例研究-1
第2周 数据分析过程-2 案例研究-1&案例研究-2
第3周 完成项目 项目:探索数据集
第4周 项目修改与通过 修改项目、查缺补漏、休息调整

!!看这里!!:在P3课程里面安排了SQL的高阶课程,但是因为在项目三中并不会涉及到SQL知识,所以为了保证大家学习的连贯性,在完成前两周的课程之后,就开始项目。至于!!SQL的高阶知识,大家可以放在课程通关后进行选修!!;

本阶段可能是个挑战,请一定要保持自信,请一定要坚持学习和总结,如果遇到任何课程问题请参照如下顺序进行解决:

饭要一口一口吃,路要一步一步走,大家不要被任务吓到,跟着导学一步一步来,肯定没问题哒!那我们开始吧!

注:本着按需知情原则,所涉及的知识点都是在数据分析过程中必须的、常用的,而不是最全面的,想要更丰富,那就需要你们课下再进一步的学习和探索!

本周目标

  • 学习课程中数据分析过程中的全部和案例研究1的部分内容,了解数据分析过程,熟练掌握Pandas在数据分析中的应用。

学习计划

时间 学习资源 学习内容
周二 微信群 - 每周导学 预览每周导学
周三、周四 Udacity - Classroom 数据分析过程&案例研究-1
周五 微信/Classin - 1V1 课程难点
周六 Classin - 优达日 本周学习总结、答疑
周日 笔记本 总结沉淀
周一 自主学习 查漏补缺

本周知识清单

前期准备&拓展

  • 课程概述给出的链接很重要,希望大家能抽空都看一看,尤其是最后的书Python for Data Analysis,目前已经出了第二版,可以戳下载链接进行下载。
  • 关于设置编程环境,本章已经不是建议了,而是要求,如果你还没有完成本地环境的配置,请戳:配置Anaconda和Jupyter Notebook

数据分析流程

数据分析不是从上至下一蹴而就的过程,而是需要你不断迭代、重复、完善,最终得到结论的过程。

提出问题

  • 数据集中的各个变量之间的相关性如何?是否存在某些联系?

  • 变量的统计结果会揭示什么?

  • 根据现有掌握的数据,能否对未来走势进行预测?

  • 根据你想了解的问题,去收集数据,再对问题进行修缮,如此迭代,获取更全面的数据,提出更一阵见血的问题。

整理数据

  • 收集

    数据库提取?直接下载?网络爬虫?

  • 评估

    这个过程是对数据产生直观印象的过程,你要尝试了解数据集的大小,基本的统计结果,是否存在数据重复?缺失?数据类型是否正确?是否每个变量成一列&每个观察值成一行?数据是否有统计错误?(严重偏离正常值,比如说气温达到70℃等等)…

  • 清理

    对评估出的问题进行逐项排查、清理,直至获取到干净的数据(推荐超级有用且经典的Tidy Data,虽然代码用的是R语言,但代码不就只是工具而已嘛,关键的是思维方法

探索性数据分析

即课程中提到的EDA(Exploratory data analysis ),这是一种分析数据集——尤其是陌生数据集——的方法,具体实施的话可以采用定量、定性的数据分析或者是可视化分析。

这是一个强调迭代的过程,在这个阶段你要不断的对数据进行探索(提问、整理、分析、可视化等等),根据你得到的结果再去丰富你的数据或者完善你的问题,最终得出结论。

这是一个考验耐心和细心的繁琐过程,所以一定要心平气和,保持工作的连贯性。(不做完一套不能睡觉?

得出结论

  • 通过可视化直接得出结论(描述、总结)
  • 统计学(预测,P4阶段会学习)
  • 机器学习算法(主要是用来做预测,课下可以学一学)

传达结果

撰写报告,和别人分享你的研究结果,所以一定要逻辑清晰、结论都要有根有据,让被分享者信服你的结论。

Pandas在数据分析中的应用

准备

  • 导入Pandas包

    1
    import pandas as pd
  • 打开文件

    1
    2
    3
    4
    5
    6
    #打开csv文件
    pd.read_csv('filename')
    #打开excel文件
    pd.read_excel('filename')
    #处理中文字符的tsv文件
    pd.read_csv('filename',sep = '\t',encoding = 'utf-8')

整理数据

  • 查看数据集数据

    1
    2
    3
    4
    5
    6
    #查看前五行
    df.head()
    #查看尾五行
    df.tail()
    #查看随机一行
    df.sample()
  • 查看数据集信息

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    #查看数据集行数和列数
    df.shape
    #查看数据集信息(列名、数据类型、每列的数据量——可以看出数据缺失情况)
    df.info()
    #查看数据集基本统计信息
    df.describe()
    #查看数据集列名
    df.columns
    #查看数据集数据缺失情况
    df.isnull().sum()
    #查看缺失列数据
    df[df['col_name'].isnull()]
    #查看数据集数据重复情况
    sum(df.duplicated())
    #查看重复数据
    df[df.duplicated()]
    #查看某列分类统计情况
    df['col_name'].value_counts()
    #查看某列唯一值
    df['col_name'].unique()
    #查看某列唯一值数量
    df['col_name'].nunique()
    #以某列对数据集进行排序
    df.sort_values(by = 'col_name',ascending = False)#False为由大至小
  • 数据筛选

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    #提取某行
    df.iloc[row_index]
    df.loc['row_name']
    #提取某几行
    df.iloc[row_index_1:row_index_2]
    #提取某列
    df['col_name']
    #提取某几列
    df[['col_name_1','col_name_2']]
    #提取某行某列的值
    df.iloc[row_index,col_index]
    df.loc['row_name','col_name']
    #筛选某列中满足某条件的数据
    df[df['col_name'] == value]#等于某值的数据,同理满足所有比较运算符
    df.query('col_name == value')#代码效果同上
    df[(df['col_name_1'] >= value_1) & (df['col_name_2'] != value_2)]#与&,或|
    df.query('(col_name_1 >= value_lower) & (col_name_2 <= value_upper)')
    df.groupby('col_name')#按col_name列进行分组
  • 清理数据

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    #删除某行
    df.drop(['row_name'],inplace = True)#若添加inplace = True,修改后的数据会覆盖原始数据
    #删除某列
    df.drop(['col_name'],axis = 1)
    #缺失值的处理
    df.fillna(mean_value)#替换缺失值
    df.dropna()#删除包含缺失值的行
    df.dropna(axis = 1, how = 'all')#只删除所有数据缺失的列
    #删除重复值
    drop_duplicates(inplace = True)
    #更改某行/列/位置数据
    用iloc或者loc直接替换修改即可
    #更改数据类型
    df['datetime_col'] = pd.to_datetime(df['datetime_col'])
    df['col_name'].astype(str)#还可以是int/float...
    #更改列名
    df.rename(columns={'A':'a', 'C':'c'}, inplace = True)

    如何处理缺失值呢?这就要根据确实数据的情况而定了,是直接删除?还是暴力平均值替换?还是分类之后再用平均值替换?还是用一些什么其他的方法,全靠你去把握了。可以看一看Python Data Science这本书中的Handling Missing Data章节,你肯定会有所收获的。

  • 合并数据(merge、concat、join、append)

    因为这里比较繁琐,而且讲起来会用到很多图表,所以进行单独讲解,链接→每周导学-第六周导学-Pandas数据融合

可视化

我会将Pandas的可视化部分与matplotlib.pyplot的可视化和seaborn/ggplot等可视化包放在下周的导学中。

导出数据

1
2
3
4
#导出csv文件
df.to_csv('filename.csv',index = False)
#导出中文字符的excel文件
df.to_excel('filename.xlsx',index = False,encoding = 'utf-8-sig')

Tip:utf-8与utf-8-sig 两种编码格式区别

项目相关

P3的项目需要你完完整整得过一遍数据分析的过程,所以呢,单独的某一个数据集肯定满足不了大家,贴心的Udacity给大家准备了几个数据集备选,戳数据集预览,挑一个自己感兴趣的先~

Don’t let yesterday take up too much of today.

Hi,同学们,本周是P2阶段的最后一周了,我们用了两周时间学习了数据类型、控制流以及脚本编写等Python基础内容,还学习了Python做数据分析两个关键的第三方包——NumPy和Pandas,接下来用了一周的时间挑战项目二,相信大家经过了高强度的学习+实战化项目,对Python及Pandas一定有了更深刻更扎实的了解,那么,本周呢我们的针对P2的知识点进行总结回顾,对项目二进行修缮拓展,为下一阶段打好基础!

时间 学习重点 对应课程
第1周 Python基础内容 数据类型和运算符、控制流、函数、脚本编写
第2周 Python数据处理内容 Numpy & Pandas - 第一、二部分
第3周 完成项目 项目:探索美国共享单车数据
第4周 项目修改与通过 修改项目、查缺补漏、休息调整

对于非小白同学来说 ,本阶段内容不是很难,希望你们能在三周内完成并通过项目;

对于小白来说,本阶段可能是个挑战,请一定要保持自信,请一定要坚持学习和总结,如果遇到任何课程问题请参照如下顺序进行解决:

饭要一口一口吃,路要一步一步走,大家不要被任务吓到,跟着导学一步一步来,肯定没问题哒!那我们开始吧!

注:本着按需知情原则,所涉及的知识点都是在数据分析过程中必须的、常用的,而不是最全面的,想要更丰富,那就需要你们课下再进一步的学习和探索!

本周目标

  • 顺利通过项目二,自行总结P2阶段的知识点。

学习计划

时间 学习资源 学习内容
周二 微信群 - 每周导学 预览每周导学
周三、周四 Udacity - Classroom 项目二
周五 微信/Classin - 1V1 课程难点
周六 Classin - 优达日 本周学习总结、答疑
周日 笔记本 总结沉淀
周一 自主学习 查漏补缺

阶段总结

在本阶段,我们学习了:

  • Python的数据类型和运算符
  • Python的循环、判断语句
  • 如何自定义Python函数
  • NumPy&Pandas的基本操作

除此之外,你还掌握了一些软件的操作:

  • Python IDE的使用(Spyder/Atom)
  • Jupyter Notebook的使用
  • Python拓展包的安装部署

不知不觉间,你还锻炼了一些软技能:

  • 编程思维(把复杂的问题分解;把新问题变成老问题;凝练解决问题的核心;算法最优解)
  • 自主学习能力(效率更高,方法更优,持续时间更长)
  • 独立解决问题的能力
  • 更积极、更自信

经过这一个月的学习,大家收获颇丰。除了硬技能之外,更重要的是软技能的锻炼,不论你从事何种工作,甚至是在生活中,编程思维和自主学习能力都会让你尝到甜头,所以请继续加油吧!

知识要点

第二周必学知识点:

  • Python数据类型和运算符

    可以先自行回想一下,python的数据类型有哪些?运算符有哪些?在这一个月的练习和项目中,他们的用途都有哪些?自己在这一章节有没有薄弱点?

  • 控制流

    重点要熟练掌握:一个条件语句和两个循环语句的用法,两个循环语句的区别,break与continue的用法,再就是enumerate函数的用法。

  • 函数

    函数的定义及变量的作用域是要熟练掌握的,lambda的话,了解就好。

第三周必学知识点:

  • Pandas数据结构

    对于Pandas中两大最重要的数据类型:Series(一维)和DataFrame(二维),熟悉他们的结构和特点,这是你用python Pandas做数据分析的基础。

  • Pandas数据操作

    本阶段主要是对Pandas中数据的基本操作进行了讲解,在P3阶段会有更多的操作技巧及练习等着大家!

  • Pandas自定义函数的调用

    常用的是apply,但两者的区别要搞清楚

  • Pandas常用数据筛选函数

    这个的话,本章涉及不多,可以等到P3学完一起总结,按照数据分析的流程,把各个阶段常用的函数做个用法列举,效果更好。

项目优化

虽然收到了项目二的通关邮件,但是你对自己的代码或者项目的完成度满意吗?大家在Uda学习,也是为生活所迫,想求上进,那既然是求上进,就别上到90%就放松下来,做就做到100%,一定要对自己负责,所以大家通关后,我会拉大家到【代码互评】的微信群,大家分享代码、分享思路,交流心得,相互挑刺,想想就觉得很棒!所以说,大家讨论完之后,这个板块还会再进行更新~

废话不多说,那么,我先来抛砖引玉,给大家简单展示下我认为的一些可以尝试去改进的地方:

get_filters()函数

  • 用户输入错误时提示再次输入;

    1
    2
    3
    4
    if ... in ...:
    ...
    else:
    print('提示:')
  • 兼容大小写,只要用户输入了正确数据,即可进行响应,比如说用户想要筛选城市chicago的数据,但是不小心输成了Chicago,也能进行正确响应。

    1
    city = city_input.lower()
  • 利用循环和函数简化重复性代码

    比如说,最开始我写的代码是:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    def get_filters():
    print('Hello! Let\'s explore some US bikeshare data!')

    #定义列表
    city_list = ['chicago','new york city','washington']
    month_list = ['all','january','february','march','april','may','june']
    day_list = ['all','monday','tuesday','wednesday','thursday','friday','saturday','sunday']

    while True:
    city = input('Q1/3:which city do you want to analyst?(chicago,new york city or washington)\n')
    if city in city_list:
    break
    else:
    print('please ensure your input is one of the examples!')

    while True:
    month = input('Q2/3:which month do you want to analyst?(all,january, february, ... , june)\n')
    if month in month_list:
    break
    else:
    print('please ensure your input is one of the examples!')

    while True:
    day = input('Q3/3:which day do you want to analyst?(all, monday, tuesday, ... sunday)\n')
    if day in day_list:
    break
    else:
    print('please ensure your input is one of the examples!')

    print('-'*40)
    return (city, month, day)

    如上,对于city、month和day三个变量来说,代码是重复的,只是变量不同输出的话术不同而已,那么就可以将这三个变量和话术对应成某个函数的参数,然后通过调用这个函数,就可以简化重复的代码。

    这个函数大概可以是这样:

    1
    2
    3
    4
    5
    6
    def phrase_input(input_prompt,err_prompt,option_list):

    user_input = input(input_prompt)
    while user_input not in option_list:
    user_input = input(err_prompt)
    return (user_input)

    改善后的代码如下所示:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    def phrase_input(input_prompt,err_prompt,option_list,get_value):

    user_input = input(input_prompt)
    while get_value(user_input) not in option_list:
    user_input = input(err_prompt)
    return (user_input.title())

    def get_filters():
    print('Hello! Let\'s explore some US bikeshare data!')

    #定义列表
    city_list = ['chicago','new york city','washington']
    month_list = ['all','january','february','march','april','may','june']
    day_list = ['all','monday','tuesday','wednesday','thursday','friday','saturday','sunday']

    #定义话术
    city_prompt = 'Q1/3:which city do you want to analyst?(Chicago,New York city or Washington)\n'
    month_prompt = 'Q2/3:which month do you want to analyst?(All,January, February, ... , June)\n'
    day_prompt = 'Q3/3:which day do you want to analyst?(All, Monday, Tuesday, ... Sunday)\n'
    err_prompt = 'Please ensure your input is one of the examples above. Please input it again:\n'

    #定义get_value函数,取输入的小写值
    get_value = lambda x: x.lower()

    #调用函数
    city = phrase_input(city_prompt,err_prompt,city_list,get_value)
    month = phrase_input(month_prompt,err_prompt,month_list,get_value)
    day = phrase_input(day_prompt,err_prompt,day_list,get_value)

    print('-'*40)
    print('Your input is : \n')
    print(city, month, day)

trip_duration_stats()函数

这个函数最大的问题就是,输出不够人性化,因为计算得来的时间计算值是xxx秒,而我们平时生活中,对于大于60s的时间更偏向于说xxx分,或者xxx小时xxx天。所以这里,为了优化输出,需要我们定义一个时间转换函数,把计算结果,更人性化地呈现。

最终代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import math
import pandas as pd
import time

def changeTime(allTime):

#定义一天、一小时、一分钟的秒数
day = 24*60*60
hour = 60*60
min = 60

#小于60s时,利用math.ceil函数向上取整
if allTime <60:
return ("%d sec(s)"%math.ceil(allTime))

#利用divmod函数,获取模和余数的元组,将模作为 天,将余数继续进行函数
elif allTime > day:
days = divmod(allTime,day)
return ("%d day(s), %s"%(int(days[0]),changeTime(days[1])))

#跟上面同理
elif allTime > hour:
hours = divmod(allTime,hour)
return ('%d hour(s), %s'%(int(hours[0]),changeTime(hours[1])))


else:
mins = divmod(allTime,min)
return ("%d min(s), %d sec(s)"%(int(mins[0]),math.ceil(mins[1])))

def trip_duration_stats(df):

print('\nCalculating Trip Duration...\n')
start_time = time.time()

total_duration = df['Trip Duration'].sum()

mean_duration = df['Trip Duration'].mean()

#利用format进行格式化输出,调用changeTime函数
print('The total travel time is around {} .'.format(changeTime(total_duration)))
print('The mean of travel time is around {} .'.format(changeTime(mean_duration)))

print("\nThis took %s seconds." % (time.time() - start_time))
print('-'*40)

出现的一些不熟悉的代码/函数详解可以戳:

ceil

利用%和format进行输出格式化

devmod

user_stats()函数

这个函数面临的问题是由于数据集导致的,因为在Washington的数据缺失了性别和出生年份列,所以本函数在调用Washington数据的时候会报错,那这里就需要try和except登场进行异常处理了。

这里的相关知识可以参考第二周导学

其他待优化的问题

比如说,你还想对数据中的哪些问题感兴趣,可以自定函数进行展示;

或者,你的代码并不符合PEP8的标准,可以参考第二周导学,进行查证。

最后

经过如上的过程,大家也能了解到代码都不是一蹴而就的,而是随着你项目的深入不断进行修改调试的过程,这和你的学习一样,是一个不断试错,螺旋上升的过程。所以说,不要怕不会,更不要怕做错,不要丢了信心和耐心,把不会的掌握,把问题解决,这才是你应该做的,大家加油!!!

Don’t let yesterday take up too much of today.

Hi,同学们,本周已经是P2阶段的第三周了,前两周我们学习了数据类型、控制流以及脚本编写等Python基础内容,还学习了Python做数据分析两个关键的第三方包——NumPy和Pandas,那么,接下来就到了检验学习、提高实战能力的时候了!

这周我们要挑战项目二:探索美国共享单车数据,争取能在本周完成项目并提交,加油!

时间 学习重点 对应课程
第1周 Python基础内容 数据类型和运算符、控制流、函数、脚本编写
第2周 Python数据处理内容 Numpy & Pandas - 第一、二部分
第3周 完成项目 项目:探索美国共享单车数据
第4周 项目修改与通过 修改项目、查缺补漏、休息调整

对于非小白同学来说 ,本阶段内容不是很难,希望你们能在三周内完成并通过项目;

对于小白来说,本阶段可能是个挑战,请一定要保持自信,请一定要坚持学习和总结,如果遇到任何课程问题请参照如下顺序进行解决:

饭要一口一口吃,路要一步一步走,大家不要被任务吓到,跟着导学一步一步来,肯定没问题哒!那我们开始吧!

注:本着按需知情原则,所涉及的知识点都是在数据分析过程中必须的、常用的,而不是最全面的,想要更丰富,那就需要你们课下再进一步的学习和探索!

本周目标

  • 完成并提交项目二。

学习计划

时间 学习资源 学习内容
周二 微信群 - 每周导学 预览每周导学
周三、周四 Udacity - Classroom 数据类型 - 脚本编写
周五 微信/Classin - 1V1 课程难点
周六 Classin - 优达日 本周学习总结、答疑
周日 笔记本 总结沉淀
周一 自主学习 查漏补缺

项目准备

环境准备

强烈建议大家完成本地环境的搭建,在本地完成此项目。搭建本地环境的方法请参考Anaconda的安装与配置一节,完成后你将获得本项目中会用到的关键软件:SpyderJupyter Notebook

文件准备

在此项目中,你将比较以下三座城市的共享单车使用情况:芝加哥、纽约市和华盛顿特区。这些数据由 Motivate 提供。

数据和项目文件下载,请参考如下步骤:

PrrMp8.png

若下载失败,请微信联系我索取。

注意:因为项目文件中使用的是python2,所以在本地环境进行编写时,请按照你的版本对个别代码进行修改,以契合你的版本。完成就可以直接提交,不必再转回python2的语法。

方法准备

在本项目中,你需要完成多个函数的编写,可以按照如下方法提高工作效率:

  1. 确定第一个函数的功能需求,并构思代码;
  2. 利用Jupyter Notebook对你构思的代码进行测试
  3. 若代码测试功能符合要求,则复制代码至Spyder,完成第一个函数的编写;
  4. 保存为.py格式的文件,在本地进行功能测试,看是否复合项目要求;
  5. 若满足要求,则按照步骤1-4对第二个函数进行编写,如此往复,完成整个项目。

大家刚打开项目文件时,先不要被代码量吓到,沉下心来,一步步做,逐一击破,一定没问题哒!

项目流程

项目概述

在此项目中,你将利用 Python 探索与以下三大美国城市的自行车共享系统相关的数据:芝加哥、纽约和华盛顿特区。你将编写代码导入数据,并通过计算描述性统计数据回答有趣的问题。你还将写一个脚本,该脚本会接受原始输入并在终端中创建交互式体验,以展现这些统计信息。

读完项目概述,大概也能了解到项目的要求有哪些了,也就是需要你去完成的任务:

  • 需要你编写一个脚本
  • 在脚本中,能够读取数据文件
  • 能够根据用户输入,完成相关统计计算,并进行回答展示结果

数据集说明

我们提供了三座城市 2017 年上半年的数据。三个数据文件都包含相同的核心列:

  • 起始时间 Start Time(例如 2017-01-01 00:07:57)
  • 结束时间 End Time(例如 2017-01-01 00:20:53)
  • 骑行时长 Trip Duration(例如 776 秒)
  • 起始车站 Start Station(例如百老汇街和巴里大道)
  • 结束车站 End Station(例如塞奇威克街和北大道)
  • 用户类型 User Type(订阅者 Subscriber/Registered 或客户Customer/Casual)

芝加哥和纽约市文件还包含以下两列:

  • 性别 Gender
  • 出生年份 Birth Year

上述数据集说明中,我们能知道三个数据集中包含有哪些列,列名是什么,这在之后进行函数编写的时候,是一个非常重要的参考。

项目要求

  • 请一定要规范注释:
    • 关键代码注释,进行解释;
    • 函数功能解释文档
  • 请保存你初次完成项目的文件作为project_0,之后先备份再修改,这样直到项目审阅成功,你能很明显的对比出自己最开始出现的问题及思考问题的短板。

get_filters()函数

代码详解:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def get_filters():
"""
函数需要询问用户三个问题来获取筛选数据的三个条件:城市、月份和周几。

函数返回的是一个元组,三个元素的数据类型都为str。
"""
print('Hello! Let\'s explore some US bikeshare data!')
# TO DO: get user input for city (chicago, new york city, washington). HINT: Use a while loop to handle invalid inputs


# TO DO: get user input for month (all, january, february, ... , june)


# TO DO: get user input for day of week (all, monday, tuesday, ... sunday)


print('-'*40)
return city, month, day

关键代码提示:

1
2
3
4
5
#获取键盘输入
input()
#循环
while ... :
...

输出示例:

PrrX38.png

load_data()函数

代码详解:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def load_data(city, month, day):
"""
该函数是对get_filters函数的一个承接,get_filters函数获取筛选条件,本函数就针对筛选条件进行数据读取。
所以本函数需要三个关键数据作为参数输入,即:城市、月份和周几。
函数的输出为筛选后的数据。

Args:
(str) city - name of the city to analyze
(str) month - name of the month to filter by, or "all" to apply no month filter
(str) day - name of the day of week to filter by, or "all" to apply no day filter
Returns:
df - Pandas DataFrame containing city data filtered by month and day
"""


return df

关键代码提示:

1
2
3
4
5
6
7
8
9
10
#pandas读取文档
pd.read_csv
#datetime格式转换
pd.to_datetime
#获取datetime的月份?周几?
datetime.dt.month
datetime.dt.weekday
#判断语句
if ... :
...

time_stats()函数

代码详解:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def time_stats(df):
"""时间计算函数
针对筛选出的数据(df),对出现频次最高的月份、周几和小时进行统计,并输出结果
"""
print('\nCalculating The Most Frequent Times of Travel...\n')
start_time = time.time()

# TO DO: display the most common month


# TO DO: display the most common day of week


# TO DO: display the most common start hour


print("\nThis took %s seconds." % (time.time() - start_time))
print('-'*40)

关键代码提示:

1
2
3
4
#获取众数
pd.Series.mode()
#输出格式化
.format()

输出示例:

PrsA3T.png

station_stats()函数

代码详解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def station_stats(df):
"""站点计算函数
针对筛选出的数据(df),对出现频次最高的起始站、终点站和起点-终点线进行统计,并输出结果"""

print('\nCalculating The Most Popular Stations and Trip...\n')
start_time = time.time()

# TO DO: display most commonly used start station


# TO DO: display most commonly used end station


# TO DO: display most frequent combination of start station and end station trip


print("\nThis took %s seconds." % (time.time() - start_time))
print('-'*40)

关键代码提示:

1
2
#字符串的链接
list_0 = list_1 + list_2

输出示例:

与time_stats()函数类似

trip_duration_stats()函数

代码详解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def trip_duration_stats(df):
"""
通勤时间计算函数
针对筛选出的数据(df),对通勤总时间和平均时间进行计算,并输出结果
"""

print('\nCalculating Trip Duration...\n')
start_time = time.time()

# TO DO: display total travel time


# TO DO: display mean travel time


print("\nThis took %s seconds." % (time.time() - start_time))
print('-'*40)

关键代码提示

1
2
3
4
#求和
.sum()
#求均值
.mean()

输出示例:

PrsmDJ.png

user_stats()函数

代码详解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def user_stats(df):
"""
用户计算函数
针对筛选出的数据(df),对不同类型的用户数量、不同性别的用户数量以及最老、最新和最多的出生年份进行统计、计算,并输出结果
"""

print('\nCalculating User Stats...\n')
start_time = time.time()

# TO DO: Display counts of user types


# TO DO: Display counts of gender


# TO DO: Display earliest, most recent, and most common year of birth


print("\nThis took %s seconds." % (time.time() - start_time))
print('-'*40)

关键代码提示

1
2
3
4
#pandas 分类同积函数
pd.Series.value_counts()
#最小最大值
.min() .max()

输出示例:

Prs38K.png

main()函数

main()函数是项目中最重要的函数,是程序的入口。

如果你接手一个项目,想快速了解项目中的代码都实现了哪些功能的话,那就要去查看main()函数,这也就是为什么叫main的原因了。

但是在本项目中,该函数并不需要大家去编写或者修改,完成以上所有函数后,就可以尝试在本地进行测试,然后提交啦~

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def main():
while True:
city, month, day = get_filters()
df = load_data(city, month, day)

time_stats(df)
station_stats(df)
trip_duration_stats(df)
user_stats(df)

restart = input('\nWould you like to restart? Enter yes or no.\n')
if restart.lower() != 'yes':
break


if __name__ == "__main__":
main()

项目提交

项目提交前,请查看:项目审阅标准,提高你的一次通过率!

总结

至此,我们已经完成了本项目,回想一下,在这个项目中:

  • 你都用到了哪些python基础函数?
  • 你都用到了哪些pandas中的函数?
  • 在你定义的不同函数中,都解决了哪些问题?
  • 项目通过之后,再想想你编写的函数是完美的吗?或者说,你有哪些想要进一步完善的?
    • 怎样提高用户的体验?比如:get_filters()函数中,用户输入了NewYork,也可以实现正确识别等等
    • 怎样保持程序不会报错?比如:华盛顿用户的性别和出生年月。
  • 除了项目中的研究内容,你还想继续探究数据中的哪些因素?

加油!!!等你们的好消息!!!

Things may come to those who wait, but only the things left by those who hustle.

Hi,同学们,经过第一周的学习,我们已经完成了项目一,是不是成就感爆棚!自信心爆棚呀!那请继续保持着这样的自信心和学习动力,继续我们的课程吧!

本周开始,我们就进入到了项目二(P2)阶段,本阶段总共包含四周,在这一个月内,我们要对Python入门进行学习,并使用这门新技术完成项目二:探索美国共享单车数据,以下便是这四周的学习安排:

时间 学习重点 对应课程
第1周 Python基础内容 数据类型和运算符、控制流、函数、脚本编写
第2周 Python数据处理内容 Numpy & Pandas - 第一、二部分
第3周 完成项目 项目:探索美国共享单车数据
第4周 项目修改与通过 修改项目、查缺补漏、休息调整

对于非小白同学来说,本阶段内容不是很难,希望你们能在三周内完成并通过项目;

对于小白来说,本阶段可能是个挑战,请一定要保持自信,请一定要坚持学习和总结,如果遇到任何课程问题请参照如下顺序进行解决:

饭要一口一口吃,路要一步一步走,大家不要被任务吓到,跟着导学一步一步来,肯定没问题哒!那我们开始吧!

注:本着按需知情原则,所涉及的知识点都是在数据分析过程中必须的、常用的,而不是最全面的,想要更丰富,那就需要你们课下再进一步的学习和探索!

本周目标

  • (必选)课程中的编程入门 - Turtle为体验课~对没有编程经验的小白同学十分友好,必看!
  • (必选)学习课程中数据类型和运算符脚本编写部分,掌握Python语言的基础。
  • (可选)配置本地编译环境。

学习计划

时间 学习资源 学习内容
周二 微信群 - 每周导学 预览每周导学
周三、周四 Udacity - Classroom 数据类型 - 脚本编写
周五 微信/Classin - 1V1 课程难点
周六 Classin - 优达日 本周学习总结、答疑
周日 笔记本 总结沉淀
周一 自主学习 查漏补缺

本周知识清单

编程入门 - Turtle

本节中,选择了python中一个画图的工具——Turtle为例,带大家在轻松有趣的画图中,了解python的变量、循环等知识,对没有编程基础的小白同学十分友好相信你们通过这节课,肯定会爱上python的,哈哈

0 (可选)环境搭建

标题后面小括号中的数字即为对应课程的第几课节,如:算术运算符(2,3)即表示对应课程中为第2、3课节。

虽然是可选,但强烈推荐大家在本地搭建Python编程环境,你所需的只是有限的几步操作,却能在之后的学习和项目中给你带来无限的便捷!

  • 强烈推荐!按照课程中,第7章节Anaconda和Jupyter Notebook的详细步骤,完成本地环境的搭建。完成后你将获得:Python的本地IDESpyder以及数据分析师最爱的交互式笔记本Jupyter Notebook
  • Spyder的简明教程,光看不顶用,一定要多实操。
  • 另外,还简单推荐一款Python的编辑器Atom,可以在官网进行下载,然后可以参考博客Atom的python插件和常用插件安装一些针对python的拓展包。没有python相关拓展包的Atom做起python来就像是 用记事本再写代码?所以一定要装拓展包哦!
  • Atom的教程,课程5里面也有涉及到;除此之外,还可参考Atom基本操作,完成拓展包的下载与安装。

安装好之后尝试你的第一个python代码吧!

1
print('Hello world!')

1 Python基础语法

想要学好一门语言,语法作为语言中法律一样的存在,是非常重要的,所以请大家一定要恪守这个法律,在初学阶段打好基础,不要养成不良的编码习惯。

  • 行与缩进

    python最具特色的就是使用缩进来表示代码块, 同一个代码块的语句必须包含相同的缩进空格数,缩进的空格数是可变的,但是有个不成文的规定就是使用4个空格的缩进。

    比如:

    1
    2
    3
    4
    if True:
    print ("True")
    else:
    print ("False")

    但如果像如下这样就会因为缩进问题报错:

    1
    2
    3
    4
    5
    6
    if True:
    print ("Answer")
    print ("True")
    else:
    print ("Answer")
    print ("False") # 缩进不一致,会导致运行错误

    报错会提示如下:

    1
    IndentationError: unindent does not match any outer indentation level

    所以,如果你的程序运行后,出现这种错误提示,那你就要检查下,你的代码缩进是不是有问题了。

  • 注释

    Python中单行注释以 # 开头,多行注释可以用多个 # 号,或者 ‘’’和 “””(主要作声明函数用),示例如下:

    1
    2
    3
    4
    5
    6
    7
    # 注释1
    # 注释2
    def hello():
    '''
    this is a print function.
    '''
    print ('Hello,Python!')
  • 更多更详细的python编写规范请参考PEP8规定。(或者查看中文版

2 数据类型和运算符

数据类型

分类

  • 数字(Number):支持整型(int)、浮点型(float)、布尔型(bool) (7,8)

    在混合计算中,python会把整型转化成浮点型

  • 字符串(String):用单引号 ‘ 或双引号 “ 括起来 (11,12)

    用+连接,用*重复;字符串截取的格式为:变量[头下标:尾下标]

  • 列表(List):写在方括号 [] 之间,用逗号分隔开的元素列表。 元素可以是数字、字符串或者列表**(17-20)**

    用+连接;截取的格式同字符串

  • 元组(Tuple):与列表类似,但是不可更改,写在小括号 () 里,元素之间用逗号隔开。**(21,22)**

    用+连接;截取的格式同字符串

  • 集合(Set):无序不重复元素的序列。 (23,24)

    筛选出列表a中的不重复元素,可以直接使用set(a)

  • 字典(Dictionary) :写在大括号{ }里,是一个无序的键(key) : 值(value)**对儿集合(25-27)**

    key必须为不可变类型,且唯一

不可变数据(3 个):Number(数字)、String(字符串)、Tuple(元组);

可变数据(3 个):List(列表)、Dictionary(字典)、Set(集合)。

相互转换

函数 描述
int(x) 将x转换为一个整数
float(x) 将x转换到一个浮点数
str(x) 将对象 x 转换为字符串
list(s) 将序列 s 转换为一个列表
set(s) 转换为集合(元素唯一)

运算符

算术运算符(2,3)

假设 a = 12, b = 26

运算符 描述 实例
+ 加,数字就是做加法/字符串就是拼接 a + b 输出结果 28
- 减,做减法 a - b 输出结果 -28
* 乘 ,数字的话就是相乘/字符串的话就是重复若干次 a * b 输出结果 312
/ 除,做除法 b / a 输出结果 2.1666666666666665 (自动转化为浮点型)
% 取模 , 即做除法后的余数 b % a 输出结果 2
** a**b 为12的26次方
// 取整,即做除法后的商 9//2 输出结果 4 , 9.0//2.0 输出结果 4.0

赋值运算符(4,5,6)

运算符 描述 实例
= 简单的赋值运算符 c = a + b 将 a + b 的运算结果赋值为 c
+= 加法赋值运算符 c += a 即 c = c + a(常用 i += 1,表示递增)
-= 减法赋值运算符 c -= a 即 c = c - a

比较运算符(9,10)

运算符 描述
== 等于;比较对象是否相等
!= 不等于; 比较两个对象是否不相等
> 大于 ; 返回x是否大于y
< 小于 ;返回x是否小于y。所有比较运算符返回1表示真,返回0表示假。这分别与特殊的变量True和False等价。注意,这些变量名的大写。
>= 大于等于;返回x是否大于等于y。
<= 小于等于;返回x是否小于等于y。

逻辑运算符

运算符 逻辑表达式 描述
and x and y 即逻辑 “与”
or x or y 即逻辑 “或”
not not x 即逻辑 “非”

成员运算符

即查看指定的序列中是否存在某值,这个序列可以是字符串、列表或者元组。

运算符 描述
in 找到值返回 True,否则返回 False。
not in 与in相反

恒等运算符

运算符 描述
is 检查两边是否恒等
is not 检查两边是否不恒等

布尔运算符

python中的True和False有多种条件判断,更详细的请戳Python中的True, False条件判断,请务必查看或者添加书签。

3 控制流

条件语句if

  • 代码模板:

    1
    2
    3
    4
    5
    6
    7
    8
    if <条件判断1>:
    <执行1>
    elif <条件判断2>:
    <执行2>
    elif <条件判断3>:
    <执行3>
    else:
    <执行4>

    注意:一定要注意缩进与对齐,尤其是有if语句嵌套的情况下。

循环语句

  • for循环

    • for循环可以遍历任何序列的项目,如一个列表或者一个字符串,通俗点说,就是把这个序列中的第一个元素到最后一个元素依次访问并执行冒号后面的语句

    • 其一般格式为:

      1
      2
      for <元素> in <序列>:
      <执行语句>
  • while循环

    • for循环和while循环,两者的相同点在于都能循环做一件重复的事情;不同点在于,for循环是在序列穷尽时停止,while循环是在条件不成立时停止。 当这个条件永远不为False时,就会出现死循环。

    • 其一般格式为:

      1
      2
      while <判断条件>:
      <执行语句>
  • break和continue

    • break 语句可以跳出 for 和 while 的循环体。

      示例:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      for letter in 'Udacity':     # for实例
      if letter == 't':
      break
      print ('当前字母为 :', letter)

      i = 10 # while实例
      while i > 0:
      print ('当期变量值为 :', i)
      i -= 1
      if i == 5:
      break

      执行语句后的输出结果为:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      当前字母为 : U
      当前字母为 : d
      当前字母为 : a
      当前字母为 : c
      当前字母为 : i
      当期变量值为 : 10
      当期变量值为 : 9
      当期变量值为 : 8
      当期变量值为 : 7
      当期变量值为 : 6
    • continue是跳过当前循环块中的剩余语句, 也就是跳过continue后面的语句

      示例:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      for letter in 'Udacity':     # for实例
      if letter == 't':
      continue
      print ('当前字母为 :', letter)

      i = 5 # while实例
      while i > 0:
      i -= 1
      if i == 3:
      continue
      print ('当期变量值为 :', i)

      执行代码后的输出结果为:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      当前字母为 : U
      当前字母为 : d
      当前字母为 : a
      当前字母为 : c
      当前字母为 : i
      当前字母为 : y
      当期变量值为 : 4
      当期变量值为 : 2
      当期变量值为 : 1
      当期变量值为 : 0

综上呢,for更适合可迭代情况下使用,while更适合不知道要循环多少次的时候使用。

  • zip函数

    • zip函数的输入位可迭代的对象,输出为对应元素的元组

    • 其一般格式为:

      1
      zip([a],[b])
    • 使用zip函数可以节约不少内存

    • 可以使用list()来转换输出zip函数的结果

    • 若zip的两个输入序列长度不一致,则以短的那个为参考

    • *zip可以理解为zip的反函数,可以将元组解压为列表

    • 查看更多

    示例:

    1
    2
    3
    4
    5
    6
    a = [1,2]
    b = [3,4]
    c = [5,6,7]
    zip_1 = zip(a,b)
    zip_2 = zip(a,c)
    a1,c1 = zip(*zip_1)

    执行代码,输出结果为:

    iO2lJH.png

  • enumerate函数

    • 该函数是将一个可遍历的数据对象(如列表、元组或字符串)组合为一个带索引和元素的元组

    • 其一般格式为:

      1
      2
      enumerate(<序列>, start=0)
      #start表示下标的起始位置
    • 常与for…in…联用

    示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    a = [1,2]

    print('起始下标为默认:')
    for i,j in enumerate(a):
    print(i,j)

    print('起始下标为1:')
    for i,j in enumerate(a,start = 1):
    print(i,j)

    执行代码,输出结果为:

    1
    2
    3
    4
    5
    6
    起始下标为默认:
    0 1
    1 2
    起始下标为1:
    1 1
    2 2

列表推导式

  • 可以简单理解为:定义一个空表,然后用表中的循环语句填充该表。

  • 其一般格式为:

    1
    [表达式 for 变量 in 序列或迭代对象]

4 函数

定义函数

  • 其一般格式为:

    1
    2
    3
    4
    5
    def 函数名(参数):
    '''
    函数说明
    '''
    函数语句
    • 函数说明是建议非必需
    • 函数语句最后以return(表达式)结尾,则返回值;若不带表达式,则返回None

参数

默认参数和关键字参数不在赘述,在此只讲述一种不定长参数

  • 若在参数前面加一个星号*,则将所有未命名的参数以元组的形式导入;
  • 若在参数前面加两个星号**,则参数会以字典的形式导入。

示例:

1
2
3
4
5
6
7
8
9
10
11
#定义函数
def tupleprint(a, *tupleb ):
'''
打印任何传入的参数
'''
print ("输出: ")
print (a)
print (tupleb)

#调用函数
tupleprint(1,2,3)

执行代码,输出结果为:

1
2
3
输出: 
1
(2, 3)

变量作用域

变量的作用域就是能访问该变量的程序部分。

  • 在python中,只有模块(module),类(class)以及函数(def、lambda)才会引入新的作用域 ,而其他如if/for/while等是不会引入新的作用域的。

  • 全局变量即可以在整个程序范围内都可以访问;局部变量只能在其被定义的函数内调用。

    示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    global_a = 0 # 这是一个全局变量
    # 定义函数
    def sum( a, b ):
    global_a = a + b # global_a在这里是局部变量.
    print ("局部变量为: ", global_a)
    return global_a

    #调用函数
    sum(1,2)
    print ("全局变量为: ", global_a)

    执行代码,输出结果为:

    1
    2
    局部变量为:  3
    全局变量为: 0
  • na当局部代码想要修改全局变量时,就会用到global和nonlocal关键字了 。

    示例:

    1
    2
    3
    4
    5
    6
    7
    8
    num = 1
    def fun1():
    global num # 需要使用 global 关键字声明
    print(num)
    num = 123
    print(num)
    fun1()
    print(num)

    执行代码,输出结果为:

    1
    2
    3
    1
    123
    123

    nonlocal的用法类似,用在嵌套函数中,当只想修改嵌套作用域的变量而非全局变量时使用。

可更改对象与不可更改对象

在数据类型中也提到过,python中的可变类型(列表、字典和集合)与不可变类型(数字,字符串和元组),那在函数中作为变量进行传递时会是怎样呢?

示例1:

1
2
3
4
5
6
7
8
#定义函数
def fun1(a):
a = 2
print(a)

b = 1
fun1(b)
print(b)

示例2:

1
2
3
4
5
6
7
def fun2(list_a):
list_a.append(2)
print(list_a)

list_b = [0,1]
fun2(list_b)
print(list_b)

尝试下,上面这两个示例的输出结果,有什么区别?

匿名函数

  • 使用lambda创建

  • 所谓匿名,就是不需要def语句

  • 拥有自己的命名空间,而且只能访问自己命名空间中的变量

  • 语法格式为:

    1
    lambda <变量>:<语句>

迭代器与生成器

了解即可,更多可以戳:参考

5 脚本编写

输入和输出

  • 输入:input函数

    示例:name = input(“请输入您的姓名:”)

  • 输出:print函数和表达式语句

    • 输出格式化:在第8课节中,出现了一个format函数,这个函数就是格式化的利器
    • 其基本用法: print('大家好,我是{},今年{}岁。'.format('Allen',25))
    • 更多用法:字符串格式化数字格式化%及format用法

错误与异常

掌握try语句的用法就好。

  • try:这是 try 语句中的唯一必需子句。该块中的代码是 Python 在 try 语句中首先运行的代码。
  • except:如果 Python 在运行 try 块时遇到异常,它将跳到处理该异常的 except 块。
  • else:如果 Python 在运行 try 块时没有遇到异常,它将在运行 try 块后运行该块中的代码。
  • finally:在 Python 离开此 try 语句之前,在任何情形下它都将运行此 finally 块中的代码,即使要结束程序,例如:如果 Python 在运行 exceptelse 块中的代码时遇到错误,在停止程序之前,依然会执行此finally 块。

读写文件

  • open()即打开文件,用法如下:

    1
    open(文件名, 读写模式)
  • 常用的读写模式:

    模式 描述
    r 只读。默认模式
    rb 二进制只读。
    r+ 读写。
    rb+ 二进制读写。
    w 写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除,不想删除可参考模式a。如果该文件不存在,创建新文件。
    wb 二进制写入。其余同上
    w+ 读写。其余同上
    wb+ 二进制读写。其余同上
    a 追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。
    ab 二进制追加。其余同上
    a+ 读写。其余同上
    ab+ 二进制追加。其余同上

导入本地模块/函数

如果觉得课程中的解释有些晦涩,可以戳:如何简单地理解Python中的if name == ‘main

项目相关

本周是P2的第一周,大家除了完成以上学习任务之外呢,还要为P2项目提前准备以下几个方面:

  • 完成本地环境的搭建
  • 下载P2的项目文件,若教室下载失败的话,请戳我微信,分享百度云给你
  • 完成项目的课节1-3,对即将挑战的项目有一个大概的了解,然后在学习中有的放矢

最后

如果项目一还没通过,请一定要抓紧时间!一定要在本周三之前顺利通关!大家一定要对自己有信心,然后,对自己狠一点!加油!

If you change nothing, nothing will change.

Hi,各位同学们,大家好,欢迎踏上数据分析的不归路列车~在发车之前,有几点需要给大家强调一下:

课程和项目

  • 课程以项目为导向,学习曲线十分平缓,我也是从一个小白一步步走过来的,所以请大家一定要对自己有信心
  • 从Teambition中,大家也能看到,我们把整体的一个大任务(入门毕业)拆分成了四个子任务(项目),在每个子任务中又拆分成了知识学习、项目提交和修改、总结沉淀三个部分,在这三个部分之中,大家还可以自行再进行切分,如此将一个大难题拆分成若干个小问题,逐个击破,十分轻松
  • 对于项目,大家一定要重视!切不可抄袭,一定要对自己负责任

如何提问

在课程学习中难免会遇到问题,请按照以下流程进行问题提问:

  • 课程知识问题

    • 先自行查找问题答案,参考:谷歌/百度搜索、菜鸟教程CSDNstackoverflowSQLCookbook
    • 若问题未解决,请将问题及其所在课程章节发送至微信群,并@助教即可
  • 非课程知识问题

    比如账号登录、课程加载等问题,请详细描述问题,反馈给班主任即可

该说的也说了个差不多,那么,请大家系好安全带做好觉悟

  • 工作可能会很忙,但是每天至少要抽出一个小时来坚持学习,否则一日废,日日废
  • 准备好一个笔记本或者有道云笔记、EverNote这种电子笔记本,用来记录学习笔记/问题
  • 自律,自律,自律!自律才能让你更自由!

准备发车!

本周目标

学习课程SQL初探,并完成(通过)项目一。

学习计划

时间 学习资源 学习内容
周二 微信群 - 每周导学 预览每周导学
周三、周四 Udacity - Classroom SQL初探、项目一
周五 微信/Classin - 1V1 课程难点
周六 Classin - 优达日 项目串讲
周日 笔记本 总结沉淀
周一 自主学习 查漏补缺

本周知识清单

课程内掌握

SQL - 格式化查询语句

  • 命令需要大写,其他内容如变量等则需要小写

  • 表和变量名中不要出现空格,可使用下划线_替代

  • 查询语句中,使用单一空格隔开命令和变量

  • 为提高代码的可移植性,请在查询语句结尾添加一个分号

    正确示范

1
2
SELECT account_id
FROM orders;

SQL - 基础命令及用法参考

语句 使用方法 其他详细信息
SELECT SELECT Col1, Col2, … 提供你需要的列
FROM FROM Table 提供列所在的表格
LIMIT LIMIT 10 限制返回的行数
ORDER BY ORDER BY Col 根据列命令表格。与 DESC 一起使用。
WHERE WHERE Col > 5 用于过滤结果的一个条件语句
LIKE WHERE Col LIKE ‘%me%’ 仅提取出列文本中具有 ‘me’ 的行
IN WHERE Col IN (‘Y’, ‘N’) 仅过滤行对应的列为 ‘Y’ 或 ‘N’
NOT WHERE Col NOT IN (‘Y’, “N’) NOT 经常与 LIKEIN 一起使用。
AND WHERE Col1 > 5 AND Col2 < 3 过滤两个或多个条件必须为真的行
OR WHERE Col1 > 5 OR Col2 < 3 过滤一个条件必须为真的行
BETWEEN WHERE Col BETWEEN 3 AND 5 一般情况下,语法比使用 AND 简单一些

示例:

1
2
3
4
5
SELECT col1, col2
FROM table1
WHERE col3 > 5 AND col4 LIKE '%os%'
ORDER BY col5
LIMIT 10;

SQL - 运算顺序

  • 在 SQL 中使用算术运算符时,采用与数学中相同的运算顺序。

  • 在 SQL中使用逻辑运算符时,要参考如下优先级顺序(操作符优先级由低到高,排列在同一行的操作符具有相同的优先级)

    优先级 操作符列表
    1 :=
    2 ||,OR,XOR
    3 &&,AND
    4 NOT
    5 BETWEEN,CASE,WHEN,THEN,ELSE
    6 =,<=>,>=,>,<=,<,<>,!=,IS,LIKE,REGEXP,IN
    7 |
    8 &
    9 <<,>>
    10 -,+
    11 *,/,DIV,%,MOD
    12 ^
    13 - (一元减号),~ (一元比特反转)
    14 !
    15 BINARY,COLLATE

    HINT:看到如上这么复杂难记的优先级表,想必你也会头大,所以,为了避免因优先级导致的逻辑错误,请一定要将逻辑语句加上小括号,这样既清晰又不易出错!

课程外了解

  • 实体关系图(Entity Relationship Diagram,ERD),是一种用于数据库设计的结构图。一幅 ERD 包含不同的符号和连接符,用于显示两个重要的信息: 系统范围内的主要实体,以及这些实体之间的相互关系

    PQaRtH.md.png

    • 实体:是一个系统内可定义的事物或概念(术语“实体”通常用来代替“表”,但它们是一样的 ),如上图中的accountsorders等,即为实体。

    • 主键(Primary Key,PK):是一种特殊的实体属性,用于界定数据库表中的记录的独特性。一个表不能有两笔(或更多)拥有相同的主键属性值的记录。在上图中,各个实体内的id即为PK。

    • 外键(Foreign Key,FK):是对主键的引用,用于识别实体之间的关系。请注意,有别于主键,外键不必是唯一的,多个记录可以共享相同的值。 在上图中,orders表中的account_id即为链接表accounts的外键。

    • 基数:基数定义了一个实与另一个实体的关系里面,某方可能出现次数。 三种常见的主要关系是一对一,一对多和多对多。

      • 一对一:

        PQaWhd.png

      • 一对多:在课程中的例子即为一对多。

        PQa2Ae.png

      • 多对多:

        PQac7D.png

项目相关

请先自行尝试完成项目,如果感觉吃力,再参考哈~

项目概览

在这个项目中,我们利用Udacity的数据库,分别提取本地和全球的气温数据,并进行可视化对比分析,观察可视化结果,给出本地及全球平均气温的走势结论。

模块化任务

数据提取

利用SQL,在项目工作区中,提取出全球气温数据和感兴趣城市的数据。

HINT

  • 在提取感兴趣的城市之前,可以先通过如下代码查看数据库中,是否存在该城市数据

    1
    2
    3
    SELECT *
    FROM city_list
    WHERE city = xxx
  • 提取出数据之后,可以先在工作区简单预览下,查看有连续记录数据的年份区间,并以这个区间作为筛选条件,重新提取数据并保存

  • 你提取出来的两个数据文件,在时间筛选上应该是一致的

数据整理

利用Excel或Google Sheet对两组数据进行预处理,计算出平均气温的移动平均值

HINT

  • 计算移动平均值采用的函数为AVERAGE
  • 两组数据的移动平均值要单独成列,并且有一个不与其他列重复且易于辨认的列名,如global_temp
  • 为方便分析,你需要将两列数据合并到同一个文件中,注意在复制粘贴时,选择粘贴选项 -> 值和数据格式,这样才会粘贴得到公式计算后的数据。

数据可视化及分析

利用Excel或Google Sheet将两组移动平均值进行线条图可视化,并对结果进行描述

结论

对可视化的分析结果进行总结,并发表结论性看法。

项目提交

提交前,请将 PDF 格式的文档压缩成zip格式的压缩包,文件名不要出现汉字或者空格,示例Allen_project_01.zip

项目提交、收到审阅结果之后请及时告知班主任或助教,让我们一起分享你的喜悦,提前祝项目顺利通过,等你好消息!

参考

提前通关了怎么办?

  • 整理学习笔记
  • 开始下一阶段的学习:找助教要下一周的导学呀~

在《Think Stats 2nd》书中的第三章提到了一个有趣的统计学悖论——课堂规模悖论。书中表述如下:


在很多美国大学和学院里,学生与教师的比例约为10:1,但是学生们经常会惊讶地发现自己课上的平均学生数大于10,造成这一现象的原因有两个:

  • 学生通常每学期修4到5门课,但是教授经常只教1门或2门;
  • 上小课的学生很少,但上大课的学生人数非常之多。

一旦我们知道了第一个原因,其效应就是显而易见的,第二个就不那么明显了。让我们来看一个例子,假设一所学院某学期开了65门课,选课的人数分布如下:

size count
5-9 8
10-14 8
15-19 14
20-24 4
25-29 6
30-34 12
35-39 8
40-44 3
45-49 2

如果你问院长,每门课平均的选课人数是多少,他会构建一个PMF( probability mass function,概率质量函数),计算出均值。

PMF是将数据中的每个值映射到其概率上,是除直方图外的另一种表示数据分布的方法。


书中的代码使用的是作者自建的一个python库thinkstats2,这里不再赘述,只是借书中的例子,用python还原如下:

1
2
3
4
5
6
#定义选课人数分布字典
d = {7:8,12:8,17:14,22:4,27:6,32:12,37:8,42:3,47:2}
#获取人数分布的array
data = numpy.array(list(d.keys())).repeat(list(d.values()))
#计算均值
act_mean = data.mean()

计算得到实际选课人数均值约为23.7。

这是我们获取全部数据之后,站在类似于上帝视角去看的结果,那么如果我们对一组学生进行调查,询问他们的课堂上有多少学生,然后再次计算均值,会发现什么呢?

首先,计算出学生观察到的分布,其中每个课堂规模值的概率受到选课学生人数的“影响”。

具体实现:假设每门课的选课人数为x,而该规模人数的课程出现的概率为p,那么通过询问,获得的该规模课程总数应该为x*p。

1
2
3
4
5
6
7
8
9
10
11
#我们先构建课程规模与课程出现概率的字典
pmf = {size:(count/65) for size,count in d.items()}#65为课程总数

#构建课程规模与询问后得到的课程计数字典,我们把它叫做偏倚分布
obs_data = {size:size*count for size,count in pmf.items()}
#计算偏倚分布的选课人数总数
sum_students = sum(list(map(lambda x:x[0]*x[1],zip(obs_data.keys(),obs_data.values()))))
#计算偏倚分布的总课程数
sum_count = sum(list(obs_data.values()))
#计算偏倚分布的选课人数均值
obs_mean = sum_students/sum_count

计算得到的结果为:29.1,比实际的均值高了约25%。

接下来,我们构建这两组数据的PMF图,能更直观一些。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#构建偏倚分布课程规模与该课程出现概率的字典
obs_pmf = {size:count/sum_count for size,count in obs_data.items()}

#可视化,并列柱状图
sns.set(style="white", context="talk")#设置样式

fig = plt.figure(figsize = (10,5))#设置图像大小
ind = np.array(list(pmf.keys()))
width = 0.4

plt.bar(ind - width,pmf.values(),label = 'actual')#实际值

plt.bar(ind + width,ano_pmf.values(),label = 'observed')#观察值

plt.xlabel('class size')
plt.ylabel('PMF')
plt.xticks(list(pmf.keys()))
plt.legend(loc='upper right');

i30ncq.png

从图中可以明显看出,在偏倚分布中,小课更少,大课更多。

同样,你也可以反向进行如上的操作。假设你希望得到一所学院的课堂规模分布,但却无法从院长处得到可靠数据,你可以采用另一个办法:选择学生的一个随机样本,进行调查,询问他们的课堂上有多少学生,然后再进行“去偏倚”的操作,这里就需要用统计得来的同等规模课程计数除以它出现的概率。

为了能在高高的墙内顺利下载安装Atom的拓展包(教程),需要在本地创建一个.apmrc文件,但是直接创建保存的话,会提示

请输入文件名,那就只能通过命令符来咯,摸索了下总结如下:

1.在你想创建文件的路径下,Shift+右击,在此处打开命令符;

2.逐一输入如下行,每输入完一行按一次回车,搞定!

1
2
3
copy con .fileext
I wanna create a file without ext.
^Z

其中,.fileext替换为你想创建的拓展名文件;

第二行替换为:你创建文件中的内容,或者可以随便输入什么,然后再用记事本打开后进行修改;

第三行可以通过Ctrl+Z或者F6进行输入。