<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 阅读笔记
 作者：方跃文 
 Email
Step1:  这有点像之前那样的，我们约定 np 代表 numpy。因为 Series 和 DataFrame 用的次数非常多，所以将其引入命名空间会更加方便
Pandas的数据结构介绍
要想顺畅得使用pandas，就必须熟悉它的两个主要数据结构：Series 和 DataFrame。虽然它们并不能解决所有问题，不过它们为大多数应用提供了一种可靠的，易于使用的基础。
Series
Series 是一种类似于一维数组的对象，它由一组数据（各种NumPy数据类型）以及一组与之相关的数据标签（即索引）组成。仅有一组数据即可产生最简单的Series。
例如：
Step2:  从上面我们可以看到，Series 的字符串表现形式为：索引在左边，值在右边。因为我们上面没有为数据指定特殊的索引，所以系统会自动创建一个 0 到 N-1 （N为数据的长度）的整数型索引。你可以通过 Series 的 values 和 index 属性获取数组表示形式和索引对象：
Step3:  大部分情况下，我们更希望去定制索引，以方便我们的使用。例如
Step4:  我们可以看到上面，与普通的numpy数组相比，我们可以通过索引的方式选取Series中的单个或者一组值。
Step5:  通过上面我们可以看出，pandas中的数组操作，都会保留索引和值之间的链接。
此外，还可以将Series看成一个定长的有序字典，因为它是索引值到数据值的一个映射。它可以用在许多原本需要字典参数的函数中：
Step6:  如果数据被存放在一个python字典中，也可以直接通过这个字典创建Series, 特别地，如果只传入一个字典，则Series中得到的索引就是原始字典中的键（有序排列）
Step7:  在上例中，sdata 中跟cities索引相匹配的三个值会被找出来并放到相应的位置上，但是由于Osaka所对应的sdata值没有找到，所以它的值为NaN，即非数字（not a number）。在Pandas中，它用于表示确实或NA值。本书中，我们使用missing或者NA表示缺失的数据。pandas的 isnull 和 notnull 函数可以用于检测缺失数据。
Step8:  Series 也有类似的实例方法：
Step9:  在这一章节之后的内容中，我们将详细讲解如何处理缺失数据。
对于许多应用而言，Series最重要的功能之一就是，它在算术运算中会自动对其不同索引的数据。这句话不太好理解，我们可以通过看下面的例子加深了解。
Step10:  关于数据对其的功能，我们之后还会详细介绍，此处暂时跳过。
Series 对象本身以及索引都有一个name属性，该属性跟pandas其他的关键功能关系非常密切：
Step11:  我们可以通过直接赋值的方式来修改Series的索引
Step12:  Quiz
Step13:  DataFrame
DataFrame是一个表格型的数据结构。它既有行索引也有列索引，所以可以被看作是由Series组成的字典。跟其他类似的数据结构（如R的data.frame)比较，DataFrame中面向行和面向列的操作基本上是平衡的。Pandas中的DataFrame区别于一般python对象（如列表、字典等一维数据结构）的地方在于，它往往以一个或者多个二维块存放。DataFrame的内部技术细节十分复杂，作者说它的复杂程度远超于本书，所以不会做讨论，而只是讨论如何应用它。
虽然DataFrame以二维数据块的方式保存数据，但是我们在实际中还是可以轻松将这它们表示为更高维度的数据。表格型数据的特征是层次化索引，这是pandas高级数据处理中需要利用的关键要素。我们之后会讨论这方面的应用
构建DataFrame的方法有很多，最常用的是一种直接传入一个由等长列表或者NumPy数组组成的字典，例如
Step14:  我们可以看到像Series一样，索引被自动加上，并且字典中的数据都被有序地排列。
如果我们指定列序列，那么DataFrame的列就会按照指定顺序进行排列：
Step15:  同Series相同，如果传入的列在数据中是没有的，那么返回的也是NA值。
Step16:  通过类似字典标记的方式或属性的方式，可以将DataFrame中的列获取为一个Series
Step17:  我们可以看出来，这个新得到的Series具有与原来DataFrame相同的索引，并且name属性也已经被相应地设置好了。
DataFrame中的行也可以通过位置或者名称的方式进行获取，例如，我们用索引字段ix：
Step18:  列可以通过赋值的方式进行修改。例如，我们可以修改frame2中NaN的history列
Step19:  将列表或数组赋值给某个列时，它的长度必须和DataFrame中的长度相匹配(其实就是不能超过原DataFrame中的长度)。如果赋值的是一个Series，就会精确匹配DataFrame中的索引，所欲的空位都将被填上缺失值：
Step20:  通过为不存在的列赋值，我们可以给DataFrame增加列，例如
Step21:  我们还可以利用 del 这个关键字来对列进行删除
Step22:  特别注意 通过索引方式返回的列只是相应数据的视图而已，并不是副本。因此，对返回的Series所做的任何就地修改都会反映到源DataFrame中。通过Series的copy方法可以显示的赋值列。
此外，还有一种常见的数据形式是嵌套字典，也就是字典的字典：
Step23:  如果把它传给DataFrame，它会被解释为：外层字典的键作为列，内层的键则作为行索引
Step24:  我们也可以对结果进行转置
Step25:  内层字典的键会被合并、排序以形成最终的索引。如果显示指定了索引，则不会进行自动排序，例如：
Step26:  这里，我重新复习一下上面DataFrame的内容。以原书数据作为参照。
Step27:  现在来看看，如何让上面这个名字为df的table增加一个新的列，列的名字叫做area,并且填入随机数
Step28:  但是需要注意的是，上面assign的方法不会直接改原有的DataFrame，而后一种方法直接给新列赋值的方法是直接修改原始DataFrame的。因为在DataFrame中，任何通过索引方式返回的Series修改，都会反应到原始的DataFrame中。而如果想利用后一种方法，但是又不想改变原来的DataFrame，那么就首先要显示的创建一个副本。
下面我展示一个创建副本，并且对副本进行列删除的操作。
Step29:  上面是对一个已经存在的DataFrame增加一个列。在利用上面的data字典进行构建DataFrame的时候，我们也可以增加一个列。例如：
Step30:  上面我展示了如何对一个已经或者新构建的DataFrame增加一个列。现在我们来看看，利用类似字典标记的方式，如何来轻松获取DataFrame中的某个特别的列。我这里介绍两种方式：
Step31:  列可以通过赋值地方式进行修改。例如我们可以给frame2中地‘debt’列填入新数据：
Step32:  值得注意的是，如果要用列表或者数组给DataFrame某个列赋值时，长度必须跟DataFrame长度一样。这也是为什么前面我在给一个已经存在的DataFrame增加新列的时候我首先利用len()得到了长度。
假设我们用一个不等的列表进行赋值时，我们会出现如下类似的错误。注意不管被赋值的数组是大于还是小于DataFrame的长度，都会出现错误。不要以为数组或者列表的长度比DataFrame的长度小，就惯性地认为会在一些位置上出现 NaN。因为DataFrame接受新数据的时候，不知道哪些位置上出现NaN，这样它自己就搞不清了，因此直接报错。
但是，如果是用Series去给DataFrame的列赋值时候，是允许长度比DataFrame的长度小的，因为Series是带index的，它可以一一匹配地去告诉DataFrame哪些位置是有数据的，而哪些地方没有并且需要用NaN填充。
Step33:  这里我再提及一次利用字典嵌套方式来创建DataFrame的方法：
Indexing, Selection, and Filtering
Indexing into a Series
Step34:  Indexing into a DataFrame
Step35:  Selection with loc and iloc
Special indexing operators loc and iloc can be used to select the subsect of the rows and columns from a DataFrame with numpy-like notation usng either axis labels (loc) or integers (iloc).
In the first example, let's select a single row and multi columns by label
Step36:  Now, let's use interger indexing method iloc to select the same subset as selected in last cell by loc
Step37:  As you can see above, we have many ways to select and rerange the data contained in a pandas project
Step38:  Integer indexes
In last subsection, I have shown the integer index method. Note that, the integer index in pandas is a little bit from the built-in Python data structures like lists and tuples.
仔细体会下面几种不同的整数index方法。
Step39:  Arithmetic and data alignment
When we are adding together pandas objects, if any index pairs are not the same, the respective index in the result will be in the union of the index pairs.
Plase see the example below
Step40:  由于s1和s2中的index有一部分是不重合的，所以那些部分就出现了 NaN。这类数据在pandas的其他算数运算中也会进行类似地传递，即以 NaN 的形式出现。
Step41:  对上述两个dataframe求和的结果中，所有在df1和df2中出现的index和columns都会出现，对于那些没有重合的index或者columns，则以NaN的结果出现。
Step42:  假设两个dataframe中没有index或者column是一致的，那么他们运算的结果会得到所有都是NaN的dataframe 例如
Step43:  相比于上个cell，我们改变一下做法，use fill_value to pass an argument (here, I use 0)
Step44:  Table
Step45:  DataFrame 和 Series 之间的运算
python中，这两者的运算有着明确的规定。先来看一个带有启发性质的例子来了解一个二维数组以及它与某行之间的差
Step46:  这就叫做 broadcasting。后面有一个专门的章节会介绍broadcasting。DataFrame和Series之间的运算也接近与此。
Step47:  By default, DataFrame and Series　之间的算数运算会把Series的index匹配到DataFrame的列，然后沿着行一直向下广播
Step48:  不过，假设Series中的索引和DataFrame中的列没有一一对应会发生什么呢？我们来看一个例子
Step49:  从上面我们可以看到，假设Series的index和DataFrame的Columns没有overlap，参与运算的的两个对象就会被重新索引以形成并集
上面我们介绍的是去匹配DataFrame中的列，然后沿着行向下braodcast，那么如果我们希望匹配行，沿着列广播呢？这是必须使用
上述表格中的算数运算方法。
例如： $\star$$\star$$\star$$\star$$\star$$\star$$\star$IMPORTANT$\star$$\star$$\star$$\star$$\star$$\star$
Step50:  Function application and mapping 函数应用和映射
NumPy's unfuncs (element-wise array method, 即元素级数组方法) can also work with pandas objects
Step51:  另外一个常见的操作是，将函数应用到由各行或者列形成的1D array上。DataFrame的apply方法即可实现这样的功能
Step52:  对于python使用者方便的是，大部分在数组中的统计函数（例 sum、mean）等也都是DataFrame的方法，因此大部分情况下并不需要使用apply方法。
例如
Step53:  除了标量之外，传递给apply的函数还可返回由多个值组成的Series：
Step54:  The reason why we call it 'applymap' is that Series itself has a 'map' method for applying an element-wise function
Step55:  Sorting and Ranking 排序和排名
对于DataFrame或者Series，我们会经常需要对数据进行重新排序等操作。
要对行或者索引进行排序，可以使用sort_index 方法，它将返回一个已排序对新对象。
下面我将据一些例子，来对Series和DataFrame的索引进行排序。
Step56:  我们注意到，上面对这个Series根据index进行了重新排序。
对于DataFrame，我们可以对按照任意任意轴进行排序。
例如
Step57:  上面，我们是对索引进行排序。如果要按照值对Series排序，则可以用order方法
Step58:  The missing values are sorted to the end of the Series by default, see exmaple
Step59:  For DataFrame, 我们可以根据需要对一个或者多个列中的值进行排序。讲一个或者多个列的名字传递给 by option of sort_values
Step60:  Ranking 的排名值从1开始，直到数组中有效数组的数量。rank 方法默认会通过‘为各组分配一个平均排名’的方式来破坏平级关系：
Step61:  此外，我们也可根据值在原数据中出现的顺序给出排名：
Step62:  我们也可以按照降序进行排名
Step63:  axis indexes with duplicate labels 带有重复值的轴索引
前面我们所接触的数据，索引值都是唯一的，并且pandas确实也有很多函数方法例如reindex都要求标签唯一。然而这并不是强制性的。我们来看看一些例子
Step64:  Using 'is_unique' can check whether the labels are unique or not
Step65:  对具有重复值的索引，数据选取行为会有些不同。
如果索引对应着多个值，那么返回的是一个
Series.原书英文第二版说，如果单值情况下，只是返回一个标量。但是我的python3环境下，单值情况下返回来的还是Series，这个可能是日后得注意的地方。
无论如何，对于index，还是尽量唯一确定比较好。避免在数据的处理中出现非不必要的错误。
Step66:  这里我再举一个DataFrame的例子，但其实和Series的用法一致
Step67:  Summarizng and computing descriptive statistics 汇总和计算描述统计
pandas 对象拥有很多常用的数学和统计方法，其中大部分属于reduction（约简）和summary（汇总） statistics，用于从DataFrame的行或者列中提取出Series或者从Series中取出值。跟NumPy数组中的类似方法相比，它们都是基于没有缺失数据的假设而建立起来的。
下面，我们来看一些例子
Step68:  调用DataFrame的sum方法能返回一个含有列小计的Series
Step69:  !!! Attention
Step70:  在Pandas中，一些方法例如 idxmin和idxmax返回的是间接统计，比如达到最小值和最大值的索引。例如下面的例子
Step71:  对于非数值型数据，describe会产生另外一种汇总统计：
Step72:  Correlation and covariance 相关系数和协方差
这里会用到来自于Yahoo！Finance的数据（stock price and volumes，即股票价格和成交量）。
需要用到andas-datareader这个pacakge，如果没有的话，需用用conda或者pip安装一下，conda的话是
conda install pandas-datareader
In the book, it get_data_yahoo, however, we cannot use it now becaues the API of yahoo was changed last year
as said by https
Step73:  corr 方法可以计算两个Series中重叠的、非NA的、按索引对齐的值的相关系数。这个我在具体的研究中也使用过。详细的请看书本好了。
因为我这里值找到了AAPL的数据，因此只有一个series。
不过为了说明我简单演示一下，只是利用copy方法做了一个副本。当然这俩series是完全相同的，所以相关系数肯定是1
与此类似的，cov 用于计算协方差即covariance
Step74:  Unique values, value counts, and membership 唯一值、值计算 、成员资格
还有一类方法可以从一维Series的值中抽取信息。To illustrate these，consider this example
Step75:  如果需要排序的话，
Step76:  从上面可以看出来，结果默认是按照频率降序排序的。value_counts 还是一个顶级的pandas方法，可以用于任何数组
或者序列
Step77:  In some cases, you may want to compute a histogram on multiple
realted columns in a DataFrame. Here, I show an example
Step78:  将 pd.value_counts 传给DataFrame的apply函数，将得到
Step79:  处理缺失数据
missing data在实际数据中是很常见的现象。
在pandas中，我们经常用 np.nan 来表示missing data。例如
Step80:  Python 中内置的None值，也会被作为NA处理
Step81:  NA处理常见方法： dropna, fillna, isnull, notnull.
滤除缺失数据
Step82:  也可以通过Bollean型索引达到这个目的
Step83:  fillna可以用于填充丢失的数据。例如
Step84:  层次化索引 hierarchical indexing
hierarchical indexing是pandas的一个重要的功能，它可以让我们以低维的形式处理高维数据。这意味着，我们可以在一个轴上
拥有两个以上的索引级别。
这里我们先从Series的例子开始
Step85:  上面就是一个简单的，所有两个层次索引的数据。如果要选取数据的子集，我们可以使用：
Step86:  进一步地，我们可以对第二层索引：
Step87:  或者
Step88:  层次化索引对实际生活和工作中的数据处理非常有帮助。
例如，上面data中的数据，我们可以使用unstack方法将它门重新
分配到一个DataFrame中去
Step89:  unstack的逆运算是stack
Step90:  对于DataFrame来说，每条轴都可以有分层索引：
Step91:  这样，我们就能方便地对这个DataFrame进行数据选取
Step92:  重排分级顺序
在实际工作中，我们也许需要时常对分层次数据上的某个轴或者某个级别进行排序。
swaplevel就是这样的方法。它可以接受两个级别编号和名称。并返回一个互相换了级别的新对象。
但是数据本身不会发生任何的变化。
Step93:  为了上面重新分级的数据有一个排序。我们还可以用到sortlevel
Step94:  根据级别汇总统计
pandas可以方便地对数据进行分级统计。
Step95:  这些其实是利用了pandas的groupby功能，以后还会继续介绍。
使用DataFrame的列
在一些情况下，我们可能会希望将列作为行索引，或者将行索引变为列。这些在pandas中都可以方便的做到。
Step96:  如果是想在原始DataFrame上改，可以用
Step97:  上面的操作中，当我门把某列作为行索引时，它自动就从列中移除了。如果我们想保留它们，可以加上drop操作
Step98:  与set_index相反，reset_index则是可以把层次化索引转化到列中。
Step99:  Visualization
由于近来在处理计算材料的结果时用到了pandas数组的可视化，所以我查阅了pandas网站documentation中可视化的部分，因此在此增加了一个visualization的subsection。
Step100:  Pandas for data analysis | scipy 2017 Tutorial | Dainiel Chen
In 2017, Dainiel Chen gave a very nice presentation in SciPy meeting. I watched his vedio in the (youtube)[https
<ASSISTANT_TASK:>
Python Code:
from pandas import Series, DataFrame
import pandas as pd
Explanation: 阅读笔记
 作者：方跃文 
 Email: fyuewen@gmail.com 
 时间：始于2017年9月12日， 结束写作于 
 第五章笔记始于2018年1月6日，结束于2018年July 20th
这一章节虽然跨度很长，不过在1月到7月之间，pandas估计已经被上百次地应用到了我地实际研究中用于数据处理.
The note on this chapter was finally finished today, I was quite happy because it has lasted
quite a long time.
第五章 pandas 入门
 时间： 2017年1月6日清晨
panas 是原书作者Wes Mckinney主要想讨论的library，毕竟Mckinney本人就是pandas的开发者。pandas可以帮助数据分析工作，特别是在处理高级数据结构时候，pandas可以简化这些复杂的工作。pandas是基于NumPy构建的，因此会让以NumPy为中心的应用变得更加简单。尽管Pandas的构建哲学基于Numpy，但是两者也是有一处显著差别的，即
While pandas adopts many coding idioms from NumPy, the biggest difference is that pandas is designed for working with tabular or heterogeneous data. NumPy, by contrast, is best suited for working with homogeneous numerical array data.
Pandas其实是Mckinney在AQR量化投资管理公司任职时候开始编写的，最初他是为了满足工作需求才编写的。之后Pandas不断壮大，使得功能越来越丰富。不过Mckinney也认为后来的Pandas有点违背了自己的初衷，因为他其实是希望它能保留简介性和易用性。
在本书中，我们做如下的约定，即
End of explanation
from pandas import Series
a = [4, 5, 2, -4]
obj = Series(a)
obj
obj2=obj+obj
obj2
Explanation: 这有点像之前那样的，我们约定 np 代表 numpy。因为 Series 和 DataFrame 用的次数非常多，所以将其引入命名空间会更加方便
Pandas的数据结构介绍
要想顺畅得使用pandas，就必须熟悉它的两个主要数据结构：Series 和 DataFrame。虽然它们并不能解决所有问题，不过它们为大多数应用提供了一种可靠的，易于使用的基础。
Series
Series 是一种类似于一维数组的对象，它由一组数据（各种NumPy数据类型）以及一组与之相关的数据标签（即索引）组成。仅有一组数据即可产生最简单的Series。
例如：
End of explanation
obj.values
obj.index # 注意，如果使用python 2，显示的结果可能在形式上有点不同。
Explanation: 从上面我们可以看到，Series 的字符串表现形式为：索引在左边，值在右边。因为我们上面没有为数据指定特殊的索引，所以系统会自动创建一个 0 到 N-1 （N为数据的长度）的整数型索引。你可以通过 Series 的 values 和 index 属性获取数组表示形式和索引对象：
End of explanation
obj2 = Series([4, 5, 2 ,-4], index=['d', 'b', 
                                    'a', 'c'])
obj2.values
obj2.index
obj2['a']
Explanation: 大部分情况下，我们更希望去定制索引，以方便我们的使用。例如
End of explanation
obj2[['a', 'b']]
import pandas as pd
from pandas import Series, DataFrame
import numpy as np
obj11 = Series(np.arange(10))
print('value of obj11 is', obj11.values)
print('index of obj11 is', obj11.index)
obj13 = Series([1,2,3,4], index=['a','b','c','d'])
print('index of obj13 is', obj13.index)
print('value of obj13 is', obj13.values)
print('print the values that are large than 3\n', obj13[obj13>2])
print(obj13['b'])
print(obj13[['b','c']])
print(obj11[2])
obj13=obj13*2
print(obj13)
Explanation: 我们可以看到上面，与普通的numpy数组相比，我们可以通过索引的方式选取Series中的单个或者一组值。
End of explanation
'b' in obj13
'e' in obj13
Explanation: 通过上面我们可以看出，pandas中的数组操作，都会保留索引和值之间的链接。
此外，还可以将Series看成一个定长的有序字典，因为它是索引值到数据值的一个映射。它可以用在许多原本需要字典参数的函数中：
End of explanation
sdata = {'Kyoto': 35000, "Tokyo": 40000, "Sendai": 30000, "Nagoya": 45000}
sdata
obj4 = Series(sdata)
print(obj4)
cities = ['Kyoto', 'Osaka', 'Sendai', 'Nagoya']
obj5=Series(sdata, index=cities)
print(obj5)
Explanation: 如果数据被存放在一个python字典中，也可以直接通过这个字典创建Series, 特别地，如果只传入一个字典，则Series中得到的索引就是原始字典中的键（有序排列）
End of explanation
pd.isnull(obj5)
pd.notnull(obj5)
Explanation: 在上例中，sdata 中跟cities索引相匹配的三个值会被找出来并放到相应的位置上，但是由于Osaka所对应的sdata值没有找到，所以它的值为NaN，即非数字（not a number）。在Pandas中，它用于表示确实或NA值。本书中，我们使用missing或者NA表示缺失的数据。pandas的 isnull 和 notnull 函数可以用于检测缺失数据。
End of explanation
obj5.isnull()
obj5.notnull()
Explanation: Series 也有类似的实例方法：
End of explanation
obj4
obj5
obj5+obj4
Explanation: 在这一章节之后的内容中，我们将详细讲解如何处理缺失数据。
对于许多应用而言，Series最重要的功能之一就是，它在算术运算中会自动对其不同索引的数据。这句话不太好理解，我们可以通过看下面的例子加深了解。
End of explanation
obj4.name = 'population'
obj4.index.name = 'cities'
obj4
obj5.name = 'area'
obj5.index.name = 'cities'
obj5
Explanation: 关于数据对其的功能，我们之后还会详细介绍，此处暂时跳过。
Series 对象本身以及索引都有一个name属性，该属性跟pandas其他的关键功能关系非常密切：
End of explanation
obj5.index=['A', 'B', 'C', 'D']
print(obj5.index)
print(obj5)
Explanation: 我们可以通过直接赋值的方式来修改Series的索引
End of explanation
import numpy as np
import pandas as pd
from pandas import Series
from numpy import  random
import string
series_value = random.randn(26)
letter_string = string.ascii_lowercase[:]
letter_list = [i for i in letter_string]
sample_series = Series(series_value, index=letter_list)
sample_series.index.name = 'lower letters'
sample_series.name = 'random values'
print(sample_series)
Explanation: Quiz: create a Series from dict, use the index from a to z. Finally name the Series.
End of explanation
import pandas as pd
from pandas import DataFrame, Series
data = {'province':['Zhejiang', 'Zhejiang', 'Zhejiang', 'Hubei', 'Hubei'],'area':[101,101,101,185,185],
       'pop':[98,98,98,100,100]}
frame1 = DataFrame(data)
frame1
Explanation: DataFrame
DataFrame是一个表格型的数据结构。它既有行索引也有列索引，所以可以被看作是由Series组成的字典。跟其他类似的数据结构（如R的data.frame)比较，DataFrame中面向行和面向列的操作基本上是平衡的。Pandas中的DataFrame区别于一般python对象（如列表、字典等一维数据结构）的地方在于，它往往以一个或者多个二维块存放。DataFrame的内部技术细节十分复杂，作者说它的复杂程度远超于本书，所以不会做讨论，而只是讨论如何应用它。
虽然DataFrame以二维数据块的方式保存数据，但是我们在实际中还是可以轻松将这它们表示为更高维度的数据。表格型数据的特征是层次化索引，这是pandas高级数据处理中需要利用的关键要素。我们之后会讨论这方面的应用
构建DataFrame的方法有很多，最常用的是一种直接传入一个由等长列表或者NumPy数组组成的字典，例如
End of explanation
DataFrame(data, columns=['province','area', 'pop'])
Explanation: 我们可以看到像Series一样，索引被自动加上，并且字典中的数据都被有序地排列。
如果我们指定列序列，那么DataFrame的列就会按照指定顺序进行排列：
End of explanation
frame2 = DataFrame(data,columns=['province', 'pop', 'area', 'history'],index=[1,2,3,4,5])
frame2
frame2.columns
frame2.index
Explanation: 同Series相同，如果传入的列在数据中是没有的，那么返回的也是NA值。
End of explanation
frame2['province']  #标记方式
frame2.province #属性方式
Explanation: 通过类似字典标记的方式或属性的方式，可以将DataFrame中的列获取为一个Series
End of explanation
frame2.ix[3]  #ix is derepted in python3, instead use iloc 
Explanation: 我们可以看出来，这个新得到的Series具有与原来DataFrame相同的索引，并且name属性也已经被相应地设置好了。
DataFrame中的行也可以通过位置或者名称的方式进行获取，例如，我们用索引字段ix：
End of explanation
frame2['history']=2000
frame2
Explanation: 列可以通过赋值的方式进行修改。例如，我们可以修改frame2中NaN的history列
End of explanation
val = Series([2000,3000,2100],index=[1,3,5])
frame2['history']=val
frame2 #index 1，3，5的 被改变了，2和4因为在val中是没有的，所以填入的是NaN
Explanation: 将列表或数组赋值给某个列时，它的长度必须和DataFrame中的长度相匹配(其实就是不能超过原DataFrame中的长度)。如果赋值的是一个Series，就会精确匹配DataFrame中的索引，所欲的空位都将被填上缺失值：
End of explanation
frame2['estern']=frame2.province=="Zhejiang" #将boolean value赋值给estern这个列
frame2 #我们看到frame2中的确增加了一个estern列
Explanation: 通过为不存在的列赋值，我们可以给DataFrame增加列，例如
End of explanation
del frame2['estern']
frame2.columns # estern coulumn was delted 
frame2["area"]=frame2["area"]+1
frame2
Explanation: 我们还可以利用 del 这个关键字来对列进行删除
End of explanation
pop = {'Nevada':{2001:2.4, 2002:2.9},
      'Ohio':{2000:1.5, 2001: 1.7, 2002:3.6}}
Explanation: 特别注意 通过索引方式返回的列只是相应数据的视图而已，并不是副本。因此，对返回的Series所做的任何就地修改都会反映到源DataFrame中。通过Series的copy方法可以显示的赋值列。
此外，还有一种常见的数据形式是嵌套字典，也就是字典的字典：
End of explanation
frame3 = DataFrame(pop)
frame3
Explanation: 如果把它传给DataFrame，它会被解释为：外层字典的键作为列，内层的键则作为行索引
End of explanation
frame3.T
Explanation: 我们也可以对结果进行转置
End of explanation
DataFrame(pop, index=[2001,2002,2000])
DataFrame(pop, columns=["Ohio", "Nevada"])
DataFrame(pop, columns=["Ohio", "Nevada"],index=[2002,2001,2000])
Explanation: 内层字典的键会被合并、排序以形成最终的索引。如果显示指定了索引，则不会进行自动排序，例如：
End of explanation
#这里我们利用一种由列表组成的字典来创建DataFrame，后面我还会提及一种利用嵌套字典来创建的方式
import pandas as pd
import numpy as np
from pandas import DataFrame
data = {'state':['Ohio','Ohio','Ohio','Nevada','Nevada'],
       'year':[2000,2001,2002,2001,2002],
       'pop':[1.5, 1.7, 3.6, 2.4, 2.9]}
frame = DataFrame(data)
frame
frame.iloc[1]
现在我们想一下，如何让这个表格按照'year','state','pop'顺序来排列？
f = DataFrame(data, columns = ['year', 'state', 'pop'])
f
f.sort_values(by=['year'])
#类似地，我们可以按照人口数量来从小到大排列。
f.sort_values(by=['pop'])
#反过来，我们根据人口数量从大到小进行排序
df = f.sort_values(by=['pop'],ascending=False) #ascend means ‘go up'.
df
Explanation: 这里，我重新复习一下上面DataFrame的内容。以原书数据作为参照。
End of explanation
sLength = len(df['year']) # 得到行的数目
print(sLength)
df1=df.assign(area=pd.Series(np.random.randn(sLength)).values)
df1
还有一种方法就是给一个新的列赋值，这也是增加列的方法：
df['area'] = pd.Series(np.random.randn(sLength)).values
df
Explanation: 现在来看看，如何让上面这个名字为df的table增加一个新的列，列的名字叫做area,并且填入随机数
End of explanation
df2=df.copy()
print(df2)
print('\n')
del df2['area']  #delet a column in df2
print(df2)
print('\n')
print(df)
Explanation: 但是需要注意的是，上面assign的方法不会直接改原有的DataFrame，而后一种方法直接给新列赋值的方法是直接修改原始DataFrame的。因为在DataFrame中，任何通过索引方式返回的Series修改，都会反应到原始的DataFrame中。而如果想利用后一种方法，但是又不想改变原来的DataFrame，那么就首先要显示的创建一个副本。
下面我展示一个创建副本，并且对副本进行列删除的操作。
End of explanation
frame2 = DataFrame(data, columns=['year','state','pop','debt'], index =['one',
                                                                       'two',
                                                                       'three',
                                                                       'four',
                                                                       'five'])
frame2
frame2.columns
Explanation: 上面是对一个已经存在的DataFrame增加一个列。在利用上面的data字典进行构建DataFrame的时候，我们也可以增加一个列。例如：
End of explanation
#方法1
frame2['pop']
#方法2
frame2.year #当我实用frame2.pop时候出现的结果和我预想的不同，这似乎是因为pop是python中毕竟特殊的关键字？
上面是从DataFrame中获取列，同样地我们也可以通过位置或名称地方式来获取行，比如用索引字段ix
frame2.ix['three']
Explanation: 上面我展示了如何对一个已经或者新构建的DataFrame增加一个列。现在我们来看看，利用类似字典标记的方式，如何来轻松获取DataFrame中的某个特别的列。我这里介绍两种方式：
End of explanation
frame2['debt']=16.5
frame2
frame2['debt']=np.arange(5.) #give a list to this 'debt' columns
frame2
Explanation: 列可以通过赋值地方式进行修改。例如我们可以给frame2中地‘debt’列填入新数据：
End of explanation
frame2['debt']=np.arange(6.) #give a list to this 'debt' columns
frame2
#这里我们再试一下用Series来赋值
from pandas import Series
val = Series([-1.2, -1.5, -1.7], index = ['two', 'four', 'five'])
frame2['debt']=val
frame2
Explanation: 值得注意的是，如果要用列表或者数组给DataFrame某个列赋值时，长度必须跟DataFrame长度一样。这也是为什么前面我在给一个已经存在的DataFrame增加新列的时候我首先利用len()得到了长度。
假设我们用一个不等的列表进行赋值时，我们会出现如下类似的错误。注意不管被赋值的数组是大于还是小于DataFrame的长度，都会出现错误。不要以为数组或者列表的长度比DataFrame的长度小，就惯性地认为会在一些位置上出现 NaN。因为DataFrame接受新数据的时候，不知道哪些位置上出现NaN，这样它自己就搞不清了，因此直接报错。
但是，如果是用Series去给DataFrame的列赋值时候，是允许长度比DataFrame的长度小的，因为Series是带index的，它可以一一匹配地去告诉DataFrame哪些位置是有数据的，而哪些地方没有并且需要用NaN填充。
End of explanation
import pandas as pd
import numpy as np
obj = pd.Series(np.arange(4.), index=['a', 'b', 'c', 'd'])
obj
type(obj)
obj[obj<2]
Explanation: 这里我再提及一次利用字典嵌套方式来创建DataFrame的方法：
Indexing, Selection, and Filtering
Indexing into a Series
End of explanation
data = pd.DataFrame(np.arange(16).reshape(4,4),
                   index=['Ohio', 'Colorado','Utah', 'New York'],
                   columns=['one', 'two', 'three', 'four'])
data
data['two']
data[['two', 'one']]
Slice DataFrame
data[::2]
data[:2]
Select data with a bollean array
data[data['three'] > 5]
data[data['three'] > 3]
Explanation: Indexing into a DataFrame: it retrieves one or more columns either with a single value or sequence
End of explanation
data.loc['Colorado']
data.loc['Colorado', ['two', 'four']]
Explanation: Selection with loc and iloc
Special indexing operators loc and iloc can be used to select the subsect of the rows and columns from a DataFrame with numpy-like notation usng either axis labels (loc) or integers (iloc).
In the first example, let's select a single row and multi columns by label:
End of explanation
data.iloc[1,[1, 3]]
data.loc[:"Colorado"]
data.loc[:"Colorado"][:1]
data.loc["Colorado"]   
# Compared to the last cell, I remove the comma :
# Hence only the row of 'Colorado'
data.loc[:"Colorado", ['two', 'three']]
data
data.iloc[[1,2],[1, 3]]
data.iloc[:, 1:3][data.three > 6]
Explanation: Now, let's use interger indexing method iloc to select the same subset as selected in last cell by loc:
End of explanation
data.at['Utah', 'two']
data.iat[2, 1]
data.reindex
data.get_value
data.set_value
Explanation: As you can see above, we have many ways to select and rerange the data contained in a pandas project
End of explanation
#For example
import numpy as np
data_list = np.arange(10).tolist()
data_list
data_list[:2]
data_df = pd.DataFrame(np.arange(9).reshape((3,3)),
                       index=['0', '1', '2'],
                       columns=['a', 'b', 'c'])
data_df
data_df.iloc[:2]
series_test = data_df.a
series_test
series = series_test[:]*0.1
type(series)
type(series_test)
ser = pd.Series(np.arange(3.))
print(type(ser))
ser
ser.loc[:2.]
Explanation: Integer indexes
In last subsection, I have shown the integer index method. Note that, the integer index in pandas is a little bit from the built-in Python data structures like lists and tuples.
仔细体会下面几种不同的整数index方法。
End of explanation
import pandas as pd
import numpy as np
from numpy.random import randn
s1 = pd.Series(randn(4), index=['a', 'b', 'c', 'd'])
s2 = pd.Series(randn(4), index=['e', 'b', 'c', 'd'])
s2
s1 + s2
Explanation: Arithmetic and data alignment
When we are adding together pandas objects, if any index pairs are not the same, the respective index in the result will be in the union of the index pairs.
Plase see the example below
End of explanation
import pandas as pd
import numpy as np
df1 = pd.DataFrame(np.arange(9).reshape((3,3)),
                  columns = list('bcd'),
                  index=['Ohio', 'Texas', 'Colorado'])
df2 = pd.DataFrame(np.arange(12).reshape((4,3)),
                  columns = list('bde'),
                  index=['Utah', 'Ohio', 'Texas', 'Oregon'])
df1
df2
Explanation: 由于s1和s2中的index有一部分是不重合的，所以那些部分就出现了 NaN。这类数据在pandas的其他算数运算中也会进行类似地传递，即以 NaN 的形式出现。
End of explanation
df1 + df2
Explanation: 对上述两个dataframe求和的结果中，所有在df1和df2中出现的index和columns都会出现，对于那些没有重合的index或者columns，则以NaN的结果出现。
End of explanation
df1 = pd.DataFrame({'A': [1,2]})
df2 = pd.DataFrame({'B': [3,4]})
print(df1)
print(df2)
df1 + df2
Explanation: 假设两个dataframe中没有index或者column是一致的，那么他们运算的结果会得到所有都是NaN的dataframe 例如
End of explanation
df1.add(df2, fill_value=0)
Explanation: 相比于上个cell，我们改变一下做法，use fill_value to pass an argument (here, I use 0)
End of explanation
1/df1
df1.rdiv(1)
df1.floordiv(df2, fill_value=4)  
# about floordiv, you can see https://www.quora.com/What-does-floor-division-in-Python-do
df1.mul(df2,fill_value=1)
df1.pow(df2, fill_value=3)
Explanation: Table:　灵活多变的算数方法
Method | description
--- | --- 
add, radd | +
sub, rsub | -
div, rdiv | /
floordiv, rfloordiv | floor division //
mul, rmul | methods for multiplication ()
pow, rpow | methods for exponentiation (*)
注意：加了字母 r 的，代表对应的 courterpart
例如 1/df1 和 df1.rdiv(1) 是等价的。
End of explanation
arr = np.arange(12.).reshape((3,4))
arr
arr[0]
arr - arr[0]
Explanation: DataFrame 和 Series 之间的运算
python中，这两者的运算有着明确的规定。先来看一个带有启发性质的例子来了解一个二维数组以及它与某行之间的差
End of explanation
frame = pd.DataFrame(np.arange(12.).reshape((4,3)),
                                          columns = list('bde'),
                                          index = ['Utah', 'Ohio', 'Texas', 'Oregon'])
frame
series = frame.iloc[0]
print(series)
Explanation: 这就叫做 broadcasting。后面有一个专门的章节会介绍broadcasting。DataFrame和Series之间的运算也接近与此。
End of explanation
frame - series
Explanation: By default, DataFrame and Series　之间的算数运算会把Series的index匹配到DataFrame的列，然后沿着行一直向下广播
End of explanation
series2 = pd.Series(range(3), index= ['b', 'e', 'f'])
frame + series2
Explanation: 不过，假设Series中的索引和DataFrame中的列没有一一对应会发生什么呢？我们来看一个例子
End of explanation
series3 = frame['d']
series
frame.sub(series3, axis=0)  # 这里传入的轴号0就是希望匹配的轴。在本立中，我们的目的是匹配DataFrame中的行索引，并进行广播
Explanation: 从上面我们可以看到，假设Series的index和DataFrame的Columns没有overlap，参与运算的的两个对象就会被重新索引以形成并集
上面我们介绍的是去匹配DataFrame中的列，然后沿着行向下braodcast，那么如果我们希望匹配行，沿着列广播呢？这是必须使用
上述表格中的算数运算方法。
例如： $\star$$\star$$\star$$\star$$\star$$\star$$\star$IMPORTANT$\star$$\star$$\star$$\star$$\star$$\star$
End of explanation
from pandas import DataFrame
import numpy as np
frame = DataFrame(np.random.randn(4,3), columns = list('bde'),
                 index = ['Utah', 'Ohio', 'Texas', 'Oregon'])
frame
np.abs(frame)
Explanation: Function application and mapping 函数应用和映射
NumPy's unfuncs (element-wise array method, 即元素级数组方法) can also work with pandas objects: 比如常见的 numpy.abs
End of explanation
f = lambda x: x.max() - x.min()
frame.apply(f)  
# alternatively, we can use frame.apply(f, axis='index')
# or frame.apply(f, axis=0)
frame.apply(f, axis=1)
# alternatively, we can use frame.apply(f, axis='columns')
# or frame.apply(f, axis=1)
Explanation: 另外一个常见的操作是，将函数应用到由各行或者列形成的1D array上。DataFrame的apply方法即可实现这样的功能
End of explanation
np.sum(frame, axis='index')
np.sum(frame, axis='columns')
Explanation: 对于python使用者方便的是，大部分在数组中的统计函数（例 sum、mean）等也都是DataFrame的方法，因此大部分情况下并不需要使用apply方法。
例如
End of explanation
# using this function
# we can print the maximum or minimum for each column of a DataFrame
from pandas import Series
def F(x):
    return Series([x.min(), x.max()], index = 
                 ['min', 'max'])
frame.apply(F)
此外，元素级的Python函数也是可以使用的。
In the following example, I will show you how to format the flowaing, i.e. keep specifiec figures for the floatings
import pandas as pd
from pandas import DataFrame, Series
import numpy as np
frame = DataFrame(np.random.randn(3,4), columns = [list('abcd')],
                 index=[list('123')])
format = lambda x: '%.2f' % x
print(frame)
df = frame.applymap(format)
df
Explanation: 除了标量之外，传递给apply的函数还可返回由多个值组成的Series：
End of explanation
series = Series([1.111,2.111,3.111], index=['a', 'c', 'b'])
series.map(format)
Explanation: The reason why we call it 'applymap' is that Series itself has a 'map' method for applying an element-wise function:
End of explanation
from pandas import DataFrame, Series
obj = Series(range(4), index = ['d', 'a', 'b', 'c'])
obj
obj.sort_index()
Explanation: Sorting and Ranking 排序和排名
对于DataFrame或者Series，我们会经常需要对数据进行重新排序等操作。
要对行或者索引进行排序，可以使用sort_index 方法，它将返回一个已排序对新对象。
下面我将据一些例子，来对Series和DataFrame的索引进行排序。
End of explanation
import numpy as np
frame = DataFrame(np.random.randn(4,3), columns=[list('dbc')],
                 index=np.arange(4).tolist())
frame
frame.sort_index(axis=0, ascending=False)
frame.sort_index(axis=1, ascending=True)
Explanation: 我们注意到，上面对这个Series根据index进行了重新排序。
对于DataFrame，我们可以对按照任意任意轴进行排序。
例如
End of explanation
obj = Series([3,12,-222,3])
obj.sort_values()  
# note that in python 2.7: obj.order()
# I highly recommend using the new feature in python3
Explanation: 上面，我们是对索引进行排序。如果要按照值对Series排序，则可以用order方法
End of explanation
import pandas as pd
obj = pd.Series([45,  np.nan, 72, 83, np.nan, -33 ])
obj
obj.sort_values()
Explanation: The missing values are sorted to the end of the Series by default, see exmaple:
note that: we use numpy.nan to represent the missing value in DataFrame or Series
End of explanation
frame = pd.DataFrame({'b':[4, 7, -3, 2], 'a':[0, 1.1, 0, 1.1]})
frame
frame.sort_values(by='b')
frame.sort_values(by=['a', 'b'])
Explanation: For DataFrame, 我们可以根据需要对一个或者多个列中的值进行排序。讲一个或者多个列的名字传递给 by option of sort_values
End of explanation
obj = Series([7, -5, 7, 4, 2, 0, 4])  
obj.rank()    #表示在这个数在原来的向量中排第几名，有相同的数，取平均
Explanation: Ranking 的排名值从1开始，直到数组中有效数组的数量。rank 方法默认会通过‘为各组分配一个平均排名’的方式来破坏平级关系：
End of explanation
obj.rank(method = 'first')  # 注意，和上一个cell中方法的区别；
Explanation: 此外，我们也可根据值在原数据中出现的顺序给出排名：
End of explanation
obj.rank(ascending=False, method='max') # 使用整个分组的最大排名
obj.rank(ascending=False, method='min')  # 使用整个分组的额最小排名
Explanation: 我们也可以按照降序进行排名
End of explanation
obj = Series(range(5), index=[list('aabbc')])
obj
Explanation: axis indexes with duplicate labels 带有重复值的轴索引
前面我们所接触的数据，索引值都是唯一的，并且pandas确实也有很多函数方法例如reindex都要求标签唯一。然而这并不是强制性的。我们来看看一些例子
End of explanation
obj.index.is_unique
Explanation: Using 'is_unique' can check whether the labels are unique or not:
End of explanation
a_series = obj['a']
print(type(a_series))
a_series
c_value = obj['c']
print(type(c_value))
print(c_value)
obj['c']
Explanation: 对具有重复值的索引，数据选取行为会有些不同。
如果索引对应着多个值，那么返回的是一个
Series.原书英文第二版说，如果单值情况下，只是返回一个标量。但是我的python3环境下，单值情况下返回来的还是Series，这个可能是日后得注意的地方。
无论如何，对于index，还是尽量唯一确定比较好。避免在数据的处理中出现非不必要的错误。
End of explanation
df = pd.DataFrame(np.random.randn(4,3), index=[list('aabb')])
df
df.loc['b']
Explanation: 这里我再举一个DataFrame的例子，但其实和Series的用法一致
End of explanation
import pandas as pd
import numpy as np
df = pd.DataFrame([[1.4, np.nan], [7.1, -4.5],
                 [np.nan, np.nan], [0.75, -1.3]],
                 index = [list('abcd')],
                 columns = ['one', 'two'])
df
Explanation: Summarizng and computing descriptive statistics 汇总和计算描述统计
pandas 对象拥有很多常用的数学和统计方法，其中大部分属于reduction（约简）和summary（汇总） statistics，用于从DataFrame的行或者列中提取出Series或者从Series中取出值。跟NumPy数组中的类似方法相比，它们都是基于没有缺失数据的假设而建立起来的。
下面，我们来看一些例子
End of explanation
df.sum()
#Passing axis = 'columns' or axis = 1 sums across the columns instead
df.sum(axis=1)
Explanation: 调用DataFrame的sum方法能返回一个含有列小计的Series
End of explanation
如果我们不想对存在NaN的值进行运算，我们可以使用
df.sum(axis=1, skipna=False)  #还有一个option是level，适用于在multiindex的情况下，目前我还没有碰到过
Explanation: !!! Attention: 原书第二版中的结果在c的地方是NaN，而且我在bidner里面测试了下原作者的notebook（https://github.com/wesm/pydata-book）
的确，也是NaN。但是即使我copy他的代码到我现在这个环境中，c的位置也称为了0.00
End of explanation
df.idxmax()
另一些方法则是直累计型的，如cumsum
df.cumsum()  
还有一些方法，则既不是约简型也不是累计行。例如
describe方法（在实际当中，这个方法被使用的相当频繁，因为可以快速的直到一个dataset大致的情况）
df.describe()
Explanation: 在Pandas中，一些方法例如 idxmin和idxmax返回的是间接统计，比如达到最小值和最大值的索引。例如下面的例子
End of explanation
obj = pd.Series(['a', 'a', 'b', 'c']*4)
obj
obj.describe()
Explanation: 对于非数值型数据，describe会产生另外一种汇总统计：
End of explanation
import pandas_datareader.data as web
import pandas as pd
all_data = {ticker: web.get_data_robinhood(ticker)
           for ticker in ['AAPL']}
            
price = pd.DataFrame({ticker: data['low_price'] #Adj Close
                    for ticker, data in all_data.items()})
# volume = pd.DataFrame({ticker: data['symbol']
#                       for ticker, data in all_data.items()})
price.head(10)
price_aapl = price['AAPL']
type(price_aapl)
price_float_appl = pd.to_numeric(price_aapl)
returns = price_float_appl.pct_change()
returns.tail()
Explanation: Correlation and covariance 相关系数和协方差
这里会用到来自于Yahoo！Finance的数据（stock price and volumes，即股票价格和成交量）。
需要用到andas-datareader这个pacakge，如果没有的话，需用用conda或者pip安装一下，conda的话是
conda install pandas-datareader
In the book, it get_data_yahoo, however, we cannot use it now becaues the API of yahoo was changed last year
as said by https://github.com/pydata/pandas-datareader/
End of explanation
returns_copy = returns.copy()
returns.corr(returns_copy)
returns.cov(returns_copy)
Explanation: corr 方法可以计算两个Series中重叠的、非NA的、按索引对齐的值的相关系数。这个我在具体的研究中也使用过。详细的请看书本好了。
因为我这里值找到了AAPL的数据，因此只有一个series。
不过为了说明我简单演示一下，只是利用copy方法做了一个副本。当然这俩series是完全相同的，所以相关系数肯定是1
与此类似的，cov 用于计算协方差即covariance
End of explanation
obj = pd.Series(['c', 'a', 'd', 'a', 'a', 'b', 'b', 'c', 'c'])
obj
uniques = obj.unique()
Explanation: Unique values, value counts, and membership 唯一值、值计算 、成员资格
还有一类方法可以从一维Series的值中抽取信息。To illustrate these，consider this example
End of explanation
uniques
sorted(uniques)
obj.value_counts()
Explanation: 如果需要排序的话，
End of explanation
pd.value_counts(obj.values, sort=False)  
#value_counts returns a Series
#containing unique values as its index and frequencies as its values,
#ordered count in descending order
obj
mask = obj.isin(['b', 'c'])
mask
type(mask)
obj[mask]
Explanation: 从上面可以看出来，结果默认是按照频率降序排序的。value_counts 还是一个顶级的pandas方法，可以用于任何数组
或者序列
End of explanation
data = pd.DataFrame({'Qu1': [1, 3, 4, 3, 4],
                     'Qu2': [2, 3, 1, 2, 3],
                     'Qu3': [1, 5, 2, 4, 4]})
data
Explanation: In some cases, you may want to compute a histogram on multiple
realted columns in a DataFrame. Here, I show an example:
End of explanation
result = data.apply(pd.value_counts).fillna(0)  # 这个以后得重新复习一下。
result
Explanation: 将 pd.value_counts 传给DataFrame的apply函数，将得到
End of explanation
import pandas as pd
import numpy as np
string_data = pd.Series(['abc', 'dh', np.nan, 'xh'])
string_data
Explanation: 处理缺失数据
missing data在实际数据中是很常见的现象。
在pandas中，我们经常用 np.nan 来表示missing data。例如
End of explanation
string_data[0] = None
string_data.isnull()
Explanation: Python 中内置的None值，也会被作为NA处理
End of explanation
from numpy import nan as NA
data = pd.Series([1, NA, 3, NA, 7])
data
data.dropna()
Explanation: NA处理常见方法： dropna, fillna, isnull, notnull.
滤除缺失数据
End of explanation
data[data.notnull()]
对于DataFrame,事情会复杂一些，得区分一下，是丢弃全NA或含有NA的行或者列。
dropna默认丢失任何含有缺失值的行：
data = pd.DataFrame([[1., 6.5, 3], [1., NA, NA],
                    [NA, NA, NA], [NA, 6.5, 3.]])
data
data.dropna()
data.dropna(how='all') # by defualt, axis=0,也就是行全含NA时，才被丢弃
data.dropna(how='all', axis=1)  # 列全为NA时，被丢弃
Explanation: 也可以通过Bollean型索引达到这个目的
End of explanation
newdata = data.fillna(2.0)
newdata
Explanation: fillna可以用于填充丢失的数据。例如
End of explanation
import pandas as pd
import numpy as np
data = pd.Series(np.random.randn(10),
                index = [['a', 'a', 
                         'a', 'b',
                         'b', 'b',
                         'c', 'c',
                         'd', 'd'],
                        [1, 2, 3, 1, 2, 3, 1, 2, 2, 3]])
data
Explanation: 层次化索引 hierarchical indexing
hierarchical indexing是pandas的一个重要的功能，它可以让我们以低维的形式处理高维数据。这意味着，我们可以在一个轴上
拥有两个以上的索引级别。
这里我们先从Series的例子开始
End of explanation
data['b']
Explanation: 上面就是一个简单的，所有两个层次索引的数据。如果要选取数据的子集，我们可以使用：
End of explanation
data['b'][1]
Explanation: 进一步地，我们可以对第二层索引：
End of explanation
data['b', 1]
Explanation: 或者
End of explanation
data.unstack()
Explanation: 层次化索引对实际生活和工作中的数据处理非常有帮助。
例如，上面data中的数据，我们可以使用unstack方法将它门重新
分配到一个DataFrame中去
End of explanation
data.unstack().stack()
Explanation: unstack的逆运算是stack:
End of explanation
frame = pd.DataFrame(np.arange(12).reshape(4,3),
                    index=[['a', 'a', 
                           'b', 'b'], [1, 2, 1, 2]],
                    columns=[['Ohio', 'Ohio', 'Colorado'],
                            ['Green', 'Red', 'Green']])
frame  # 下面中，会打印出轴标签
frame.index.names = ['key1', 'key2']
frame.columns.names = ['state', 'color']
frame
Explanation: 对于DataFrame来说，每条轴都可以有分层索引：
End of explanation
frame['Ohio']
Explanation: 这样，我们就能方便地对这个DataFrame进行数据选取
End of explanation
frame.swaplevel('key1', 'key2')
Explanation: 重排分级顺序
在实际工作中，我们也许需要时常对分层次数据上的某个轴或者某个级别进行排序。
swaplevel就是这样的方法。它可以接受两个级别编号和名称。并返回一个互相换了级别的新对象。
但是数据本身不会发生任何的变化。
End of explanation
frame.swaplevel('key1', 'key2').sort_index(level='key2')
Explanation: 为了上面重新分级的数据有一个排序。我们还可以用到sortlevel
End of explanation
frame.sum(level='color', axis=1)
frame.sum(level='key2', axis=0)
Explanation: 根据级别汇总统计
pandas可以方便地对数据进行分级统计。
End of explanation
frame = pd.DataFrame({'a': range(7), 'b': range(7, 0, -1),
                     'c': ['one', 'one', 'one', 'two', 'two', 'two', 'two'],
                     'd': [0, 1, 2, 0, 1, 2, 3]})
frame_back = frame.copy()
frame_back
frame2 = frame.set_index(['c'])
frame3 = frame.set_index(['c', 'd'])
frame2
frame3
Explanation: 这些其实是利用了pandas的groupby功能，以后还会继续介绍。
使用DataFrame的列
在一些情况下，我们可能会希望将列作为行索引，或者将行索引变为列。这些在pandas中都可以方便的做到。
End of explanation
frame_back.set_index(['c'], inplace=True)
frame_back
Explanation: 如果是想在原始DataFrame上改，可以用
End of explanation
frame.set_index(['c'], drop=False)
Explanation: 上面的操作中，当我门把某列作为行索引时，它自动就从列中移除了。如果我们想保留它们，可以加上drop操作
End of explanation
frame2.reset_index()
Explanation: 与set_index相反，reset_index则是可以把层次化索引转化到列中。
End of explanation
%matplotlib inline
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
ts = pd.Series(np.random.randn(1000), index = pd.date_range(
    '1/1/2000', periods = 1000))
ts = ts.cumsum()
ts.plot()
df = pd.DataFrame(np.random.randn(1000, 4), 
                  index = ts.index, columns = list('ABCD'))
df = df.cumsum()
plt.figure(); df.plot();
df3 = pd.DataFrame(np.random.randn(1000,2), columns
                   = ['B', 'C']).cumsum()
df3['A'] = pd.Series(list(range(len(df))))
#pass logy to get a log-scale y-axis
ts = pd.Series(np.random.randn(1000), index=pd.date_range('1/1/2000', periods=1000))
ts = np.exp(ts.cumsum())
ts.plot(logy=True)
df.A.plot()
df.B.plot(secondary_y=True, style='g')
#To plot some columns in a DataFrame, give the column names to the secondary_y keyword:
plt.figure()
ax = df.plot(secondary_y=['A', 'B'])
ax.set_ylabel('CD scale')
ax.right_ax.set_ylabel('AB scale')
plt.figure()
# plt.show()
df.plot(secondary_y=['A', 'B'], mark_right=False) #set false to turn off the automatic marking
Explanation: Visualization
由于近来在处理计算材料的结果时用到了pandas数组的可视化，所以我查阅了pandas网站documentation中可视化的部分，因此在此增加了一个visualization的subsection。
End of explanation
import pandas as pd
#check the version of the padas you are using
pd.__version__
print('the version of pandas in my computer is', pd.__version__)
pd.read_csv('./chapter05/data/gapminder.tsv', delimiter='\t').head(10)
pd.read_csv('./chapter05/data/gapminder.tsv', delimiter='\t').head() # 如果括号中不指定，默认是5，所以只打印出表格的前面五行
#let us specify df for the imported file
df = pd.read_csv("./chapter05/data/gapminder.tsv", delimiter='\t')
df
df.head(10)
type(df)
df.shape
df.shape() #you will see an error because as you see above, df.shape is a tuple
df.info()
Explanation: Pandas for data analysis | scipy 2017 Tutorial | Dainiel Chen
In 2017, Dainiel Chen gave a very nice presentation in SciPy meeting. I watched his vedio in the (youtube)[https://www.youtube.com/watch?v=oGzU688xCUs], hence I added some note in this section. All the imported files mentioned in this section can be found in Chen's github (repo.)[https://github.com/chendaniely/scipy-2017-tutorial-pandas]. For my convenience, I moved the folder 'data' in his repo to chapter05 in my current repo.
End of explanation
<END_TASK>