import numpy as np
import pandas as pd

index  = pd.date_range('1/1/2000', periods=8)
s = pd.Series(np.random.randn(5), index=['a', 'b', 'c', 'd', 'e'])
df = pd.DataFrame(np.random.randn(8, 3), index=index, columns=['A', 'B', 'C'])
wp = pd.Panel(np.random.randn(2,5,4), items=['Item1', 'Item2'], major_axis=pd.date_range('1/1/2000',periods=5),
             minor_axis=['A', 'B', 'C', 'D'])

"""
Explanation: 数据结构的内置方法
这一节介绍常用的pandas数据结构内置方法。很重要的一节。
创建本节要用到的数据结构。
End of explanation
"""


long_series = pd.Series(np.random.randn(1000))

long_series.head()

long_series.tail(3)

"""
Explanation: Head() Tail()
想要预览Series或DataFrame对象，可以使用head()和tail()方法。默认显示5行数据，你也可以自己设置显示的行数。
End of explanation
"""


df[:2]

df.columns = [x.lower() for x in df.columns] #将列名重置为小写

df

"""
Explanation: 属性和 ndarray
pandas对象有很多属性，你可以通过这些属性访问数据。

shape: 显示对象的维度，同ndarray
坐标label


Series: index




DataFrame: index(行)和columns




Panel:  items, major_axis and minor_axis



可以通过属性进行安全赋值。
End of explanation
"""


s.values

df.values

type(df.values)

wp.values

"""
Explanation: 只想得到对象中的数据而忽略index和columns，使用values属性就可以
End of explanation
"""


df = pd.DataFrame({'one' : pd.Series(np.random.randn(3), index=['a', 'b', 'c']),
                       'two' : pd.Series(np.random.randn(4), index=['a', 'b', 'c', 'd']),
                       'three' : pd.Series(np.random.randn(3), index=['b', 'c', 'd'])})

df

row = df.ix[1]
row

column = df['two']

column

df.sub(row, axis='columns')

df.sub(row, axis=1)

df.sub(row, axis='index')

df.sub(row, axis=0)

"""
Explanation: 如果DataFrame或Panel对象的数据类型相同(比如都是 int64)，修改object.values相当于直接修改原对象的值。如果数据类型不相同，则根本不能对values属性返回值进行赋值。
注意:
如果对象内数据类型不同，values返回的ndarray的dtype将是能够兼容所有数据类型的类型。比如，有的列数据是int，有的列数据是float，.values返回的ndarray的dtype将是float。
加速的操作
pandas从0.11.0版本开始使用numexpr库对二值数值类型操作加速，用bottleneck库对布尔操作加速。
加速效果对大数据尤其明显。
这里有一个速度的简单对比，使用100,000行* 100列的DataFrame:

所以，在安装pandas后也要顺便安装numexpr, bottleneck。
灵活的二元运算
在所有的pandas对象之间的二元运算中，大家最感兴趣的一般是下面两个：
* 高维数据结构（比如DataFrame）和低维数据结构（比如Series）之间计算时的广播(broadcasting)行为
* 计算时有缺失值
广播
DataFrame对象内置add(), sub(), mul(), div()以及radd(), rsub(),...等方法来进行二元操作。
使用这些方法时，你可以通过axis参数来决定广播时匹配index还是columns:
End of explanation
"""


df

df2 = pd.DataFrame({'one' : pd.Series(np.random.randn(3), index=['a', 'b', 'c']),
                       'two' : pd.Series(np.random.randn(4), index=['a', 'b', 'c', 'd']),
                       'three' : pd.Series(np.random.randn(4), index=['a', 'b', 'c', 'd'])})

df2

df + df2

 df.add(df2, fill_value=0) #注意['a', 'three']不是NaN

"""
Explanation: 填充缺失值
在Series和DataFrame中，算术运算方法(比如add())有一个fill_value参数，含义很明显，计算前用一个值来代替缺失值，然后再参与运算。注意，如果参与运算的两个object同一位置(同行同列)都是NaN，fill_value不起作用，计算结果还是NaN。
看例子：
End of explanation
"""


df.gt(df2)

df2.ne(df)

"""
Explanation: 灵活的比较操作
pandas引入了二元比较运算方法：eq, ne, lt, gt, le。
End of explanation
"""


df>0

(df>0).all() #与操作

(df > 0).any()#或操作

"""
Explanation: 意思操作返回一个和输入对象同类型的对象，值类型为bool，返回结果可以用于检索。
布尔降维 Boolean Reductions
pandas提供了三个方法(any(), all(), bool())和一个empty属性来对布尔结果进行降维。
End of explanation
"""


(df > 0).any().any()

"""
Explanation: 同样可以对降维后的结果再进行降维。
End of explanation
"""


df.empty

pd.DataFrame(columns=list('ABC')).empty

"""
Explanation: 使用empty属性检测一个pandas对象是否为空。
End of explanation
"""


pd.Series([True]).bool()

pd.Series([False]).bool()

pd.DataFrame([[True]]).bool()

pd.DataFrame([[False]]).bool()

"""
Explanation: 对于只含有一个元素的pandas对象，对其进行布尔检测，使用bool():
End of explanation
"""


df + df == df*2

(df+df == df*2).all()

"""
Explanation: 比较对象是否相等
一个问题通常有多种解法。一个最简单的例子：df+df和df*2。为了检测两个计算结果是否相等，你可能想到：(df+df == df*2).all()，然而，这样计算得到的结果是False：
End of explanation
"""


np.nan == np.nan

"""
Explanation: 为什么df + df == df*2 返回的结果含有False？因为NaN和NaN比较厚结果为False！
End of explanation
"""


(df+df).equals(df*2)

"""
Explanation: 还好pandas提供了equals()方法解决上面NaN之间不想等的问题。
End of explanation
"""


df1 = pd.DataFrame({'c':['f',0,np.nan]})
df1

df2 = pd.DataFrame({'c':[np.nan, 0, 'f']}, index=[2,1,0])
df2

df1.equals(df2)

df1.equals(df2.sort_index()) #对df2的索引排序，然后再比较

"""
Explanation: 注意：
在使用equals()方法进行比较时，两个对象如果数据不一致必为False。甚至是如果label的顺序不一致也返回False。
End of explanation
"""


pd.Series(['foo', 'bar', 'baz']) == 'foo'

pd.Index(['foo', 'bar', 'baz']) == 'foo'

"""
Explanation: 不同类型的对象之间 逐元素比较
你可以直接对pandas对象和一个常量值进行逐元素比较：
End of explanation
"""


pd.Series(['foo', 'bar', 'baz']) == pd.Index(['foo', 'bar', 'qux'])

pd.Series(['foo', 'bar', 'baz']) == np.array(['foo', 'bar', 'qux'])

pd.Series(['foo', 'bar', 'baz']) == pd.Series(['foo', 'bar']) #长度不相同

"""
Explanation: 不同类型的对象(比如pandas数据结构、numpy数组)之间进行逐元素的比较也是没有问题的，前提是两个对象的shape要相同。
End of explanation
"""


np.array([1,2,3]) == np.array([2])

np.array([1, 2, 3]) == np.array([1, 2])

"""
Explanation: 但要知道不同shape的numpy数组之间是可以直接比较的！因为广播！即使无法广播，也不会Error而是返回False。
End of explanation
"""


df1 = pd.DataFrame({'A' : [1., np.nan, 3., 5., np.nan],
                    'B' : [np.nan, 2., 3., np.nan, 6.]})
df1

df2 = pd.DataFrame({'A' : [5., 2., 4., np.nan, 3., 7.],
                        'B' : [np.nan, np.nan, 3., 4., 6., 8.]})
df2

df1.combine_first(df2)

"""
Explanation: combine_first()
看一下例子：
End of explanation
"""


combiner = lambda x,y: np.where(pd.isnull(x), y,x)

df1.combine(df2, combiner)

"""
Explanation: 解释：
对于df1中NaN的元素，用df2中对应位置的元素替换！
DataFrame.combine()
DataFrame.combine()方法接收一个DF对象和一个combiner方法。
End of explanation
"""


df

df.mean() #axis=0, 计算每一列的平均值

df.mean(1) #计算每一行的平均值

"""
Explanation: 统计相关 的方法
Series, DataFrame和Panel内置了许多计算统计相关指标的方法。这些方法大致分为两类：
* 返回低维结果，比如sum(),mean(),quantile()
* 返回同原对象同样大小的对象，比如cumsum(), cumprod()
总体来说，这些方法接收一个坐标轴参数:
* Series不需要坐标轴参数
* DataFrame 默认axis=0(index), axis=1(columns)
* Panel 默认axis=1(major), axis=0(items), axis=2(minor)
End of explanation
"""


df.sum(0, skipna=False)

df.sum(axis=1, skipna=True)

"""
Explanation: 所有的这些方法都有skipna参数，含义是计算过程中是否剔除缺失值，skipna默认值为True。
End of explanation
"""


ts_stand = (df-df.mean())/df.std()

ts_stand.std()

xs_stand = df.sub(df.mean(1), axis=0).div(df.std(1), axis=0)

xs_stand.std(1)

"""
Explanation: 这些函数可以参与算术和广播运算。
比如：
End of explanation
"""


df.cumsum()

"""
Explanation: 注意cumsum() cumprod()方法 保留NA值的位置。
End of explanation
"""


series = pd.Series(np.random.randn(500))
series[20:500]=np.nan

series[10:20]=5

series.nunique()

series

"""
Explanation: 下面列出常用的方法及其描述。提醒每一个方法都有一个level参数用于具有层次索引的对象。
|    方法     | 描述  | 
| ------------- |:-------------:| 
| count      | 沿着坐标轴统计非空的行数| 
| sum      | 沿着坐标轴取加和| 
| mean | 沿着坐标轴求均值|  
|mad|沿着坐标轴计算平均绝对偏差|
|median|沿着坐标轴计算中位数|
|min|沿着坐标轴取最小值|
|max|沿着坐标轴取最大值|
|mode|沿着坐标轴取众数|
|abs|计算每一个值的绝对值|
|prod|沿着坐标轴求乘积|
|std|沿着坐标轴计算标准差|
|var|沿着坐标轴计算无偏方差|
|sem|沿着坐标轴计算标准差|
|skew|沿着坐标轴计算样本偏斜|
|kurt|沿着坐标轴计算样本峰度|
|quantile|沿着坐标轴计算样本分位数，单位%|
|cumsum|沿着坐标轴计算累加和|
|cumprod|沿着坐标轴计算累积乘|
|cummax|沿着坐标轴计算累计最大|
|cummin|沿着坐标轴计算累计最小|
Note：所有需要沿着坐标轴计算的方法，默认axis=0，即将方法应用到每一列数据上。
Series还有一个nunique()方法返回非空数值 组成的集合的大小。
End of explanation
"""


series = pd.Series(np.random.randn(1000))
series[::2]=np.nan

series.describe()

frame = pd.DataFrame(np.random.randn(1000, 5), columns=['a', 'b', 'c', 'd', 'e'])

frame.ix[::2]=np.nan

frame.describe()

"""
Explanation: descrieb()， 数据摘要
describe()方法非常有用，它计算数据的各种常用统计指标(比如平均值、标准差等)，计算时不包括NA。拿到数据首先要有大概的了解，使用describe()方法就对了。
End of explanation
"""


series.describe(percentiles=[.05, .25, .75, .95])

"""
Explanation: 默认describe()只包含25%, 50%, 75%, 也可以通过percentiles参数进行指定。
End of explanation
"""


s = pd.Series(['a', 'a', 'b', 'b', 'a', 'a', np.nan, 'c', 'd', 'a'])

s.describe()

"""
Explanation: 如果Series内数据是非数值类型，describe()也能给出一定的统计结果
End of explanation
"""


frame = pd.DataFrame({'a':['Yes', 'Yes', 'NO', 'No'], 'b':range(4)})

frame.describe()

"""
Explanation: 如果DataFrame对象有的列是数值类型，有的列不是数值类型，describe()仅对数值类型的列进行计算。
End of explanation
"""


frame.describe(include=['object']) #只对非数值列进行统计计算

frame.describe(include=['number'])

frame.describe(include='all')#'all'不是列表

"""
Explanation: 如果非要知道非数值列的统计指标呢？describe提供了include参数，取值范围{'object', 'number', 'all'}。
看一下例子, 注意'object'和'number'都是在列表中，而'all'不需要放在列表中：
End of explanation
"""


s1 = pd.Series(np.random.randn(5))
s1

s1.idxmin(), s1.idxmax() #最小值：-0.296405, 最大值：1.735420

df1 = pd.DataFrame(np.random.randn(5,3), columns=list('ABC'))
df1

df1.idxmin(axis=0)

df1.idxmax(axis=1)

"""
Explanation: 最大/最小值对应的index
idxmin(), idxmax()返回最小值和最大值对应的index。
End of explanation
"""


df3 = pd.DataFrame([2, 1, 1, 3, np.nan], columns=['A'], index=list('edcba'))
df3

df3['A'].idxmin()

"""
Explanation: 如果多个数值都是最大值或最小值，idxmax() idxmin()返回最大值、最小值第一次出现对应的索引值
End of explanation
"""


data = np.random.randint(0, 7, size=50)
data

s = pd.Series(data)

s.value_counts()

pd.value_counts(data) #也是全局方法

"""
Explanation: 实际上，idxmin和idxmax就是NumPy中的argmin和argmax。
value_counts() 数值计数
value_counts()计算一维度数据结构的直方图。
End of explanation
"""


s5 = pd.Series([1,1,3,3,3,5,5,7,7,7])

s5.mode()

df5 = pd.DataFrame({"A": np.random.randint(0, 7, size=50),
                    "B": np.random.randint(-10, 15, size=50)})

df5

df5.mode()

"""
Explanation: 虽然前面介绍过mode()方法了，看两个例子吧：
End of explanation
"""


arr = np.random.randn(20)

factor = pd.cut(arr, 4)

factor

factor = pd.cut(arr, [-5, -1, 0, 1, 5]) #输入 离散区间

factor

"""
Explanation: 区间离散化
cut() qcut()方法可以对连续数据进行离散化
End of explanation
"""


arr = np.random.randn(30)

factor = pd.qcut(arr, [0, .25, .5, .75, 1])

factor

pd.value_counts(factor)

"""
Explanation: qcut()方法计算样本的分位数，比如我们可以将正态分布的数据 进行四分位数离散化：
End of explanation
"""


arr = np.random.randn(20)

factor = pd.cut(arr, [-np.inf, 0, np.inf])

factor

"""
Explanation: 离散区间也可以用极限定义
End of explanation
"""


#f, g 和h是三个方法，接收DataFrame对象，返回DataFrame对象
f(g(h(df), arg1=1), arg2=2, arg3=3)

"""
Explanation: 函数应用
如果你想用自己写的方法或其他库方法操作pandas对象，你应该知道下面的三种方式。 具体选择哪种方式取决于你是想操作整个DataFrame对象还是DataFrame对象的某几行或某几列，或者逐元素操作。

管道 pipe()
基于列或行的函数应用 apply()
对DataFrame对象逐元素计算 applymap()

管道
DataFrame和Series当然能够作为参数传入方法。然而，如果涉及到多个方法的序列调用，推荐使用pipe()。看一下例子：
End of explanation
"""


(df.pipe(h).pipe(g, arg1=1).pipe(f, arg2=2, arg3=3))

"""
Explanation: 上面一行代码推荐用下面的等价写法:
End of explanation
"""


df.apply(np.mean)

df.apply(np.mean, axis=1)

df.apply(lambda x: x.max() - x.min())

df.apply(np.cumsum)

df.apply(np.exp)

"""
Explanation: 注意 f g h三个方法中DataFrame都是作为第一个参数。如果DataFrame作为第二个参数呢？方法是为pipe提供(callable, data_keyword)，pipe会自动调用DataFrame对象。
比如，使用statsmodels处理回归问题，他们的API期望第一个参数是公式，第二个参数是DataFrame对象data。我们使用pipe传递(sm.poisson, 'data'):

pipe灵感来自于Unix中伟大的艺术：管道。pandas中pipe()的实现很简洁，推荐阅读源代码pd.DataFrame.pipe
基于行或者列的函数应用
任意函数都可以直接对DataFrame或Panel某一坐标轴进行直接操纵，只需要使用apply()方法即可，同描述性统计方法一样，apply()方法接收axis参数。
End of explanation
"""


tsdf = pd.DataFrame(np.random.randn(1000, 3), columns=['A', 'B', 'C'],
                   index=pd.date_range('1/1/2000', periods=1000))
tsdf

tsdf.apply(lambda x:x.idxmax())

"""
Explanation: 灵活运用apply()方法可以统计出数据集的很多特性。比如，假设我们希望从数据中抽取每一列最大值的索引值。
End of explanation
"""


def subtract_and_divide(x, sub, divide=1):
    return (x - sub)/divide

df.apply(subtract_and_divide, args=(5,),divide=3)

"""
Explanation: apply()方法当然支持接收其他参数了，比如下面的例子：
End of explanation
"""


df

df.apply(pd.Series.interpolate)

"""
Explanation: 另一个有用的特性是对DataFrame对象传递Series方法，然后针对DF对象的每一列或每一行执行 Series内置的方法！
End of explanation
"""


df4 = pd.DataFrame(np.random.randn(4, 3),index=['a','b','c','d'],columns=['one', 'two', 'three'])
df4

f = lambda x:len(str(x))

df4['one'].map(f)

df4.applymap(f)

"""
Explanation: 对单个元素应用Python方法
既然不是所有的方法都能被向量化(接收NumPy数组，返回另一个数组或者值),但是DataFrame内置的applymap()和Series的map()方法能够接收任意的接收一个值且返回一个值的Python方法。
End of explanation
"""


s = pd.Series(['six', 'seven', 'six', 'seven', 'six'], index=['a', 'b', 'c', 'd', 'e'])

t = pd.Series({'six':6., 'seven':7.})

s

t

s.map(t)

"""
Explanation: Series.map()还有一个功能是模仿merge(), join()
End of explanation
"""


s = pd.Series(np.random.randn(5), index=['a','b','c','d','e'])

s

s.reindex(['e', 'b', 'f', 'd'])

"""
Explanation: reindex和改变label
reindex()是pandas中基本的数据对齐方法。其他所有依赖label对齐的方法基本都要靠reindex()实现。reindex(重新索引)意味着是沿着某条轴转换数据以匹配新设定的label。具体来说，reindex()做了三件事情：
* 对数据进行排序以匹配新的labels
* 如果新label对应的位置没有数据，插入缺失值NA
* 可以指定调用fill填充数据。
下面是一个简单的例子：
End of explanation
"""


df

df.reindex(index=['c', 'f', 'b'], columns=['three', 'two', 'one'])

"""
Explanation: 对于DataFrame来说，你可以同时改变列名和索引值。
End of explanation
"""


rs = s.reindex(df.index)

rs

rs.index is df.index

"""
Explanation: 如果只想改变列或者索引的label，DataFrame也提供了reindex_axis()方法，接收label和axis。
End of explanation
"""


df2 = pd.DataFrame(np.random.randn(3, 2),index=['a','b','c'],columns=['one', 'two'])

df2

df

df.reindex_like(df2)

"""
Explanation: 上面一行代码顺便说明了Series的索引和DataFrame的索引是同一类的实例。
重新索引来和另一个对象对齐 reindex_like()
你可能想传递一个对象，使得原来对象的label和传入的对象一样，使用reindex_like()即可。
End of explanation
"""


s = pd.Series(np.random.randn(5), index=['a', 'b', 'c', 'd', 'e'])


s1 = s[:4]
s2 = s[1:]

s1

s2

s1.align(s2)

s1.align(s2, join='inner') #交集是 'b', 'c', 'd'

"""
Explanation: 使用align() 是两个对象相互对齐
align()方法是让两个对象同事对齐的最快方法。它含有join参数，
* join='outer': 取得两个对象的索引并集，这也是join的默认值。
* join='left': 使用调用对象的索引值
* join='right'：使用被调用对象的索引值
* join='inner': 使用两个对象的索引交集
align()方法返回一个元组，元素元素是重新索引的Series对象。
End of explanation
"""


df

df2 = df.iloc[:5,:2]

df2

df.align(df2, join='inner')

df.align(df2)

"""
Explanation: 对于DataFrame来说，join方法默认会应用到索引和列名。
End of explanation
"""


df.align(df2, join='inner', axis=0)

"""
Explanation: align()也含有一个axis参数，指定仅对于某一坐标轴进行对齐。
End of explanation
"""


df.align(df2.ix[0], axis=1)

"""
Explanation: DataFrame.align()同样能接收Series对象，此时axis指的是DataFrame对象的索引或列。
End of explanation
"""


rng = pd.date_range('1/3/2000', periods=8)

ts = pd.Series(np.random.randn(8), index=rng)

ts2 = ts[[0, 3, 6]]

ts

ts2

ts2.reindex(ts.index)

ts2.reindex(ts.index, method='ffill') #索引小那一行的数值填充NaN

ts2.reindex(ts.index, method='bfill') #索引大的非NaN的数值填充NaN

ts2.reindex(ts.index, method='nearest')

"""
Explanation: 重索引时顺便填充数值
reindex()方法还有一个method参数，用于填充数值,method取值如下：
* pad/ffill: 使用后面的值填充数值
* bfill/backfill: 使用前面的值填充数值
* nearest: 使用最近的索引值进行填充
以Series为例，看一下：
End of explanation
"""


ts2.reindex(ts.index).fillna(method='ffill')

"""
Explanation: method参数要求索引必须是有序的：递增或递减。
除了method='nearest',其他method取值也能用fillna()方法实现：
End of explanation
"""


ts2.reindex(ts.index, method='ffill', limit=1)

ts2

ts

ts2.reindex(ts.index, method='ffill', tolerance='1 day')

"""
Explanation: 二者的区别是：如果索引不是有序的，reindex()会报错，而fillna()和interpolate()不会检查索引是否有序。
重索引时 有条件地填充NaN
limit和tolerance参数会对填充操作进行条件限制，通常限制填充的次数。
End of explanation
"""


df

df.drop(['A'], axis=1)

"""
Explanation: 移除某些索引值
和reindex()方法很相似的是drop()，用于移除索引的某些取值。
End of explanation
"""


s

s.rename(str.upper)

"""
Explanation: 重命名索引值
rename() 方法可以对索引值重新命名，命名方式可以是字典或Series，也可以是任意的方法。
End of explanation
"""


df = pd.DataFrame({'one' : pd.Series(np.random.randn(3), index=['a', 'b', 'c']),
                   'two' : pd.Series(np.random.randn(4), index=['a', 'b', 'c', 'd']),
                    'three' : pd.Series(np.random.randn(3), index=['b', 'c', 'd'])})
df

df.rename(columns={'one' : 'foo', 'two' : 'bar'},
          index={'a' : 'apple', 'b' : 'banana', 'd' : 'durian'})

"""
Explanation: 唯一的要求是传入的函数调用索引值时必须有一个返回值，如果你传入的是字典或Series，要求是索引值必须是其键值。这点很好理解。
End of explanation
"""


s.rename('sclar-name')

"""
Explanation: 默认情况下修改的仅仅是副本，如果想对原对象索引值修改，inplace=True.
在0.18.0版本中，rename方法也能修改Series.name
End of explanation
"""


df = pd.DataFrame({'col1' : np.random.randn(3), 'col2' : np.random.randn(3)},
                  index=['a', 'b', 'c'])
df

for col in df: #产生的是列名
    print col

"""
Explanation: 迭代操作 Iteration
pandas中迭代操作依赖于具体的对象。迭代Series对象时类似迭代数组,产生的是值，迭代DataFrame或Panel对象时类似迭代字典的键值。
一句话，(for i in object)产生:
* Series: 值
* DataFrame: 列名
* Panel: item名
看一下例子吧：
End of explanation
"""


for item, frame in df.iteritems():
    print item, frame

"""
Explanation: pandas对象也有类似字典的iteritems()方法来迭代(key, value)。
为了每一行迭代DataFrame对象，有两种方法：
* iterrows(): 按照行来迭代(index, Series)。会把每一行转为Series对象。
* itertuples(): 按照行来迭代namedtuples. 这种方法比iterrows()快，大多数情况下推荐使用此方法。
警告：
迭代pandas对象通常会比较慢。所以尽量避免迭代操作，可以用以下方法替换迭代：
* 数据结构的内置方法，索引或numpy方法等
* apply()
* 使用cython写内循环
警告：
当迭代进行时永远不要有修改操作。
iteritems()
类似字典的接口，iteritems()对键值对进行迭代操作：
* Series: (index, scalar value)
* DataFrame: (column, Series)
* Panel: (item, DataFrame)
看一下例子：
End of explanation
"""


for row_index, row in df.iterrows():
    print  row_index, row

"""
Explanation: iterrows()
iterrows()方法用于迭代DataFrame的每一行，返回的是索引和Series的迭代器，但要注意Series的dtype可能和原来每一行的dtype不同。
End of explanation
"""


for row in df.itertuples():
    print row

"""
Explanation: itertuples()
itertuples()方法迭代DataFrame每一行，返回的是namedtuple。因为返回的不是Series，所以会保留DataFrame中值的dtype。
End of explanation
"""


s = pd.Series(pd.date_range('20160101 09:10:12', periods=4))

s

s.dt.hour

s.dt.second

s.dt.day

"""
Explanation: .dt 访问器
Series对象如果索引是datetime/period,可以用自带的.dt访问器返回日期、小时、分钟。
End of explanation
"""


s = pd.Series(pd.date_range('20130101', periods=4))

s

s.dt.strftime('%Y/%m/%d')

"""
Explanation: 改变时间的格式也很方便，Series.dt.strftime()
End of explanation
"""


s = pd.Series(['A', 'B', 'C', 'Aaba', 'Baca', np.nan, 'CABA', 'dog', 'cat'])

s

s.str.lower()

"""
Explanation: ## 字符串处理方法
Series带有一系列的字符串处理, 默认不对NaN处理。
End of explanation
"""


unsorted_df = df.reindex(index=['a', 'd', 'c', 'b'],
                         columns=['three', 'two', 'one'])
unsorted_df

unsorted_df.sort_index()

unsorted_df.sort_index(ascending=False)

unsorted_df.sort_index(axis=1)

unsorted_df['three'].sort_index() # Series

"""
Explanation: 排序
排序方法可以分为两大类： 按照实际的值排序和按照label排序。
按照index排序 sort_index()
Series.sort_index(), DataFrame.sort_index(), 参数是ascending, axis。
End of explanation
"""


df1 = pd.DataFrame({'one':[2,1,1,1],'two':[1,3,2,4],'three':[5,4,3,2]})
df1

df1.sort_values(by='two')

df1.sort_values(by=['one', 'two'])

"""
Explanation: 按照值排序
Series.sort_values(), DataFrame.sort_values()用于按照值进行排序，参数有by
End of explanation
"""


s[2] = np.nan

s.sort_values()

s.sort_values(na_position='first') #将NA放在前面

"""
Explanation: 通过na_position参数处理NA值。
End of explanation
"""


ser = pd.Series([1,2,3])

ser.searchsorted([0, 3]) #元素0下标是0， 元素3下标是2。注意不同元素之间是独立的，所以元素3的位置是2而不是插入0后的3.

ser.searchsorted([0, 4]) 

ser.searchsorted([1, 3], side='right')

ser.searchsorted([1, 3], side='left')

ser = pd.Series([3, 1, 2])

ser.searchsorted([0, 3], sorter=np.argsort(ser))

"""
Explanation: searchsorted()
Series.searchsorted()类似numpy.ndarray.searchsorted()。 找到元素在排好序后的位置(下标)。
End of explanation
"""


s = pd.Series(np.random.permutation(10))
s

s.sort_values()

s.nsmallest(3)

s.nlargest(3)

"""
Explanation: 最小/最大值
Series有nsmallest() nlargest()方法能够返回最小或最大的n个值。如果Series对象很大，这两种方法会比先排序后使用head()方法快很多。
End of explanation
"""


df = pd.DataFrame({'a': [-2, -1, 1, 10, 8, 11, -1],
                      'b': list('abdceff'),
                       'c': [1.0, 2.0, 4.0, 3.2, np.nan, 3.0, 4.0]})

df

df.nlargest(5, 'a') #列 'a'最大的3个值

df.nlargest(5, ['a', 'c'])

df.nsmallest(3, 'a')

df.nsmallest(5, ['a', 'c'])

"""
Explanation: 从v0.17.0开始，DataFrame也有了以上两个方法。
End of explanation
"""


df1 = pd.DataFrame({'one':[2,1,1,1],'two':[1,3,2,4],'three':[5,4,3,2]})

df1.columns = pd.MultiIndex.from_tuples([('a','one'),('a','two'),('b','three')])

df1

df1.sort_values(by=('a','two'))

"""
Explanation: 多索引列 排序
如果一列是多索引，你必须指定全部每一级的索引。
End of explanation
"""


df = pd.DataFrame(dict(A = np.random.rand(3),
                            B = 1,
                           C = 'foo',
                            D = pd.Timestamp('20010102'),
                           E = pd.Series([1.0]*3).astype('float32'),
                                        F = False,
                                       G = pd.Series([1]*3,dtype='int8')))

df

df.dtypes

"""
Explanation: 复制
copy()方法复制数据结构的值并返回一个新的对象。记住复制操作不到万不得已不使用。 比如，改变DataFrame对象值的几种方法：
* inserting, deleting, modifying a column
* 为索引、列 赋值
* 对于同构数据，直接使用values属性修改值。
几乎所有的方法都不对原对象进行直接修改，而是返回修改后的一个新对象！如果原对象数据被修改，肯定是你显示指定的修改操作。
## dtypes属性
pandas对象的主要数据类型包括: float, int, bool, datetime64[ns], datetime64[ns, tz], timedelta[ns], category, object. 除此之外还有更具体的说明存储比特数的数据类型比如int64, int32。
DataFrame的dtypes属性返回一个Series对象，Series值是DF中每一列的数据类型。
End of explanation
"""


df['A'].dtype

"""
Explanation: Series同样有dtypes属性
End of explanation
"""


pd.Series([1,2,3,4,5,6.])

pd.Series([1,2,3,6.,'foo'])

"""
Explanation: 如果pandas对象的一列中有多种数据类型，dtype返回的是能兼容所有数据类型的类型，object范围最大的。
End of explanation
"""


df.get_dtype_counts()

"""
Explanation: get_dtype_counts()方法返回DataFrame中每一种数据类型的列数。
End of explanation
"""


df1 = pd.DataFrame(np.random.randn(8, 1), columns=['A'], dtype='float32')

df1

df1.dtypes

df2 = pd.DataFrame(dict( A = pd.Series(np.random.randn(8), dtype='float16'),
                         B = pd.Series(np.random.randn(8)),
                         C = pd.Series(np.array(np.random.randn(8), dtype='uint8')) )) #这里是float16， uint8
df2

df2.dtypes

"""
Explanation: 数值数据类型可以在ndarray，Series和DataFrame中传播。
End of explanation
"""


pd.DataFrame([1, 2], columns=['a']).dtypes

pd.DataFrame({'a': [1, 2]}).dtypes

pd.DataFrame({'a': 1}, index=list(range(2))).dtypes

"""
Explanation: 数据类型的默认值
整型的默认值蕾西int64，浮点型的默认类型是float64，和你用的是32位还是64位的系统无关。
End of explanation
"""


frame = pd.DataFrame(np.array([1, 2])) #如果是在32位系统，数据类型int32

"""
Explanation: Numpy中数值的具体类型则要依赖于平台。
End of explanation
"""


df1.dtypes

df2.dtypes

df1.reindex_like(df2).fillna(value=0.0).dtypes

df3 = df1.reindex_like(df2).fillna(value=0.0) + df2

df3.dtypes

"""
Explanation: upcasting
不同类型结合时会upcast，即得到更通用的类型，看例子吧：
End of explanation
"""


df3

df3.dtypes

df3.astype('float32').dtypes

"""
Explanation: astype()方法
使用astype()显示的进行转型。默认会返回原对象的副本，即使数据类型不变。当然可以传递copy=False参数直接对原对象转型。
End of explanation
"""


df3['D'] = '1.'

df3['E'] = '1'

df3

df3.dtypes #现在'D' 'E'两列都是object类型

df3.convert_objects(convert_numeric=True).dtypes

df3['D'] = df3['D'].astype('float16')

df3['E'] = df3['E'].astype('int32')

df3.dtypes

"""
Explanation: 对object类型进行转型
convert_objects()方法能对object类型进行转型。如果想转为数字，参数是convert_numeric=True。
End of explanation
"""


df = pd.DataFrame({'string': list('abc'),
                    'int64': list(range(1, 4)),
                    'uint8': np.arange(3, 6).astype('u1'),
                    'float64': np.arange(4.0, 7.0),
                    'bool1': [True, False, True],
                    'bool2': [False, True, False],
                    'dates': pd.date_range('now', periods=3).values,
                    'category': pd.Series(list("ABC")).astype('category')})

df

df['tdeltas'] = df.dates.diff()

df['uint64'] = np.arange(3, 6).astype('u8')

df['other_dates'] = pd.date_range('20130101', periods=3).values

df['tz_aware_dates'] = pd.date_range('20130101', periods=3, tz='US/Eastern')

df

df.dtypes

"""
Explanation: 基于dtype 选择列
select_dtypes()方法实现了基于列dtype的构造子集方法。
End of explanation
"""


df.select_dtypes(include=[bool])

df.select_dtypes(include=['bool'])

df.dtypes

df.select_dtypes(include=['number', 'bool'], exclude=['unsignedinteger'])

"""
Explanation: select_dtypes()有两个参数：include, exclude。含义是要选择的列的dtype和不选择列的dtype。
End of explanation
"""


df.select_dtypes(include=['object'])

"""
Explanation: 如果要选择字符串类型的列，必须使用object类型。
End of explanation
"""


def subdtypes(dtype):
        subs = dtype.__subclasses__()
        if not subs:
            return dtype
        return [dtype, [subdtypes(dt) for dt in subs]]
   

subdtypes(np.generic)

"""
Explanation: 如果想要知道某种数据类型的所有子类型，比如numpy.number类型，你可以定义如下的方法：
End of explanation
"""


