代码可直接执行
import numpy as np
import pandas as pd
import os,time
print("Pandas的Series对象:")
#Pandas 的Series 对象是一个带索引数据构成的一维数,用一个数组创建Series 对象.
data = pd.Series([0.25, 0.5, 0.75, 1.0])
print(data)#out类似于enumerate函数的索引+数据
#Series对象将一组数据和一组索引绑定在一起,我们可以通过values 属性和index 属性获取数据
print("values:\n",data.values)
print("index:\n",data.index)#Out[4]: RangeIndex(start=0, stop=4, step=1)
data[1]#Out[5]: 0.5
print(data[1:3])#切片时会同时显示索引
"""
NumPy 数组通过隐式定义的整数索引获取数值,而Pandas 的Series 对象用一种显式定义的索引与数值关联。
显式索引的定义让Series 对象拥有了更强的能力。索引可以是任意想要的类型,例如字符串定义索引:
"""
data = pd.Series([0.25, 0.5, 0.75, 1.0],
index=['a', 'b', 'c', 'd'])
print("\n字符串索引:\n",data)
#可以把series看出一种特殊的字典,Series对象其实是一种将类型键映射到一组类型值的数据结构。
population_dict = {'California': 38332521,
'Texas': 26448193,
'New York': 19651127,
'Florida': 19552860,
'Illinois': 12882135}
population = pd.Series(population_dict)#用Python 的字典创建一个Series对象(最后都会返回类型信息)
print(population)#Pandas Series 的类型信息使得它在某些操作上比Python 的字典更高效
population['California']
print(population['Texas':'Florida'])#除了支持正常字典获取,还支持数组形式的操作
print("\n创建Series对象")
"""常规创建pd.Series(data, index=index)index 是一个可选参数,data 参数支持多种数据类型,
pd.Series({2:'a', 1:'b', 3:'c'})data可以是字典,index默认是排序字典的键"""
a=pd.Series(5, index=[100, 200, 300])#data也可以是标量创建Series时会重复填充到每个索引上
print(a)
#每一种形式都可以通过显式指定索引筛选需要的结果:
a=pd.Series({2:'a', 1:'b', 3:'c'}, index=[3, 2])#注意这里Series对象只会保留显式定义的键值对。
print(a)
print("\nPandas的DataFrame对象")
"""
你可以把二维数组看成是有序排列的一维数组一样,你也可以把DataFrame
看成是有序排列的若干Series 对象。这里的“排列”指的是它们拥有共同的索引。
"""
area_dict = {'California': 423967, 'Texas': 695662, 'New York': 141297,
'Florida': 170312, 'Illinois': 149995}
area = pd.Series(area_dict)#美国五个州面积的数据创建一个新的Series
#下面再结合之前创建的population 的Series 对象,用一个字典创建一个包含这些信息的二维:
states = pd.DataFrame({'population': population,
'area': area})
print(states)
print("获取行索引:\n",states.index)#返回行索引
print("获取列索引:\n",states.columns)#DataFrame 还有一个columns 属性,是存放列标签的Index 对象
#DataFrame 可以看作一种通用的NumPy 二维数组,它的行与列都可以通过索引获(数字索引或数字切片获取)
#可以将Series看成特殊的字典一个键映射一个值,而DataFrame 是一列映射一个Series 的数据
print("\narea:\n",states['area'])#返回area一列的数据以及行索引(列索引为KEY,对应列数组为value)
#DataFrame与np数组不同的是,np的data[0]返回的是行,而dataframe的data["col0"]返回的是列
print("\n获取行:\n",states[0:2])# or print(states["California":"New York"])
#print(states[0])#注意这样会错误,因为没有0这个key,可以写成[0:1]这样来获取行信息!!!!!!!
print("\n创建DataFrame对象")
print("(1) 通过单个Series 对象创建:")
a=pd.DataFrame(population, columns=['population'])#population是上面创建的series对象
print(a)
print("\n(2) 通过字典列表创建:")
#任何元素是字典的列表都可以变成DataFrame(说的是列表内嵌套的是字典元素)
data = [{'a': i, 'b': 2 * i} for i in range(3)]
print(data)
a=pd.DataFrame(data)
print(a)
#即使字典中有些键不存在,Pandas 也会用缺失值NaN(不是数字,not a number)来表示:
a=pd.DataFrame([{'a': 1, 'b': 2}, {'b': 3, 'c': 4}])#!!!!!!!!!
print(a)
#(3) 通过Series 对象字典创建:(上面第一个例子)
print("\n(4) 通过NumPy 二维数组创建:")
a=pd.DataFrame(np.random.rand(3, 2), columns=['foo', 'bar'], index=['a', 'b', 'c'])
print(a)
print("\n(5) 通过NumPy 结构化数组创建:")
A = np.zeros(3, dtype=[('A', 'i8'), ('B', 'f8')])
print(A)
B=pd.DataFrame(A)
print(B)
#感觉通常情况下用4 5方法创建比较多。
print("\nPandas的Index对象")
"""Pandas的Index 对象可以将它看作是一个不可变数组或有序集合
(实际上是一个多集,因为Index 对象可能会包含重复值)"""
ind = pd.Index([2, 3, 5, 7, 11])
print(ind)
print(ind[1])
print(ind[::2])
#Index对象与NumPy数组之间的不同在于,Index对象的索引是不可变的,不能通过通常的方式进行调整:
#ind[1] = 0会报错,Index 对象的不可变特征使得多个DataFrame 和数组之间进行索引共享时更加安全
#Index 对象遵循Python 标准库的集合(set)数据结构的许多习惯用法,包括并集、交集、差集等:
indA = pd.Index([1, 3, 5, 7, 9])
indB = pd.Index([2, 3, 5, 7, 11])
print(indA & indB)
print(indA | indB)
print(indA ^ indB)
#这些操作还可以通过调用对象方法来实现,例如indA.intersection(indB)。
print("\n数据取值与选择")
#Series数据选择方法:,Series 对象与一维NumPy 数组和标准Python 字典在许多方面都一样。
print("将Series看作字典:")
data = pd.Series([0.25, 0.5, 0.75, 1.0], index=['a', 'b', 'c', 'd'])
print('a' in data)
print(data.keys())
print(list(data.items()))
data['e'] = 1.25#Series对象还可以用字典语法调整数据(修改或新增)
print("\n将Series看作一维数组")
#具备和NumPy 数组一样的数组数据选择功能,包括索引、掩码、花哨的索引等操作
print(data['a':'c'])#相当于np数组的[1:2]只是index变成了可变的多类型和显性显示
print(data[0:2])#!!!1还可以用隐式整数索引作为切片
#使用显式索引作切片时,结果包含最后一个索引;而当使用隐式索引结果不包含最后一个索引
a=data[(data > 0.3) & (data < 0.8)]# 掩码
print("掩码:\n",a)
print("花哨的索引\n",data[['a', 'e']])# 花哨的索引
print("\n索引器:loc、iloc和ix")
"""切片和取值的习惯用法经常会造成混乱如果你的Series 是显式整数索引,那
么data[1] 这样的取值操作会使用显式索引,而data[1:3] 这样的切片操作却会使用隐式
索引。由于整数索引很容易造成混淆,所以Pandas 提供了一些索引器(indexer)属性来作为取值
的方法"""
data = pd.Series(['a', 'b', 'c'], index=[1, 3, 5])#这种类型的索引会造成混乱
print("\nloc 属性:\n",data.loc[1:3])#第一种索引器是loc 属性,表示取值和切片都是显式的
print("\niloc 属性:\n",data.iloc[1:3])#第二种是iloc属性,表示取值和切片都是Python 形式隐式索引
#第三种取值属性是ix,它是前两种索引器的混合形式ix 索引器主要用于DataFrame 对象
print("\nDataFrame数据选择方法")
#DataFrame在有些方面像二维或结构化数组,在有些方面又像一个共享索引的若干Series 对象构成的字典.
area = pd.Series({'California': 423967, 'Texas': 695662,
'New York': 141297, 'Florida': 170312,
'Illinois': 149995})
pop = pd.Series({'California': 38332521, 'Texas': 26448193,
'New York': 19651127, 'Florida': 19552860,
'Illinois': 12882135})
data = pd.DataFrame({'area':area, 'pop':pop})
print(data)
print("\n1.将DataFrame看作字典:")
"""把DataFrame 当作一个由若干Series 对象构成的字典两个Series
分别构成DataFrame 的一列,可以通过对列名进行字典形式的取值获取数据:"""
print(data['area'])
data.area#纯字符串列名的数据可以用属性形式
print(data.area is data['area'])#用==会进行每项对比,得出布尔值
#属性形式的数据选择不是通用的,如果列名不是纯字符串,或者列名与DF的方法同名,那么就不能用属性索引
#例如data.pop is data['pop'] out:false ,DataFrame 有一个pop()名方法
#另外,应该避免对用属性形式选择的列直接赋值
data['density'] = data['pop'] / data['area']#用字典形式修改添加字典内容。
print(data)
print("\n将DataFrame看作二维数组")
#可以把DataFrame 看成是一个增强版的二维数组,用values 属性按行查看数组数据:
print(data.values)
print("行列转置:\n",data.T)
#通过字典形式对列进行取值显然会限制我们把DataFrame 作为NumPy 数组可以获得的能力:
#print(data.values[0])获取行 ;#print(data['area'])#获取列
#因此,在进行数组形式的取值时,我们就需要用Pandas 索引器loc、iloc 和ix 了
#通过iloc 索引器,我们就可以像对待NumPy 数组一样索引Pandas的底层数组
print("iloc:\n",data.iloc[:3, :2])#获取隐形索引的第前3行和前2列
print("loc:\n",data.loc[:'Florida', :'pop'])#使用显型索引
#使用ix 索引器可以实现一种混合效果
print("ix:\n",data.ix[:3, :'pop'])#ix 索引器在整数索引的处理容易让人混淆
#loc 索引器中结合使用掩码与花哨的索引方法:
a=data.loc[data.density > 100, ['pop', 'density']] #`!!!!!!!!!!
print(a)
data.iloc[0, 2] = 90#任何一种取值方法都可以用于调整数据和NumPy 的常用方法是相同的
print(data)
print("\n其他取值方法")
#如果对单个标签取值就选择列,而对多个标签用切片就选择行:
print(data['Florida':'Illinois'])#对多个标签用切片就选择行
#切片也可以不用索引值,而直接用行数来实现:
print(data[1:3])
#掩码操作也可以直接对每一行进行过滤,而不需要使用loc 索引器:
print(data[data.density > 100])
# pd对象[]内直接切片或数字index的都是取行;单个标签取列或[["a","b"]]两个括号内的内容取列
print("\nPandas数值运算方法")
"""对于一元运算(像函数与三角函数),这些通用函数将在输出结果中保留索
引和列标签;而对于二元运算(如加法和乘法),Pandas 在传递
通用函数时会自动对齐索引进行计算。这就意味着,保存数据内容与组合不同来源的数
据——两处在NumPy 数组中都容易出错的地方——变成了Pandas 的杀手锏"""
#所谓一元和二元运算,说的是参与运算的对象或者变量的数量是一个还是两个
print("通用函数:保留索引(一元运算)")
rng = np.random.RandomState(42)
ser = pd.Series(rng.randint(0, 10, 4))#创建4个0-10的随机数组成数组,然后将数组转化为Series对象
print(ser)
df = pd.DataFrame(rng.randint(0, 10, (3, 4)), columns=['A', 'B', 'C', 'D'])
print(df)
#下面两个对象使用np通用函数生成结果是另一个保留索引的pd对象。
print(np.exp(ser))#e**x次方
print(np.sin(df * np.pi / 4))#!!!!注意这俩个都是用np.xx的np通用函数
#numpy 通用函数都可以按照类似的方式使用。!!!!
print("\n通用函数:索引对齐(二元运算)")
print("Series索引对齐")
#整合两个数据源的数据,一个是美国面积最大的三个州的面积数据,一个是美国人口最多的三个州的人口数据
area = pd.Series({'Alaska': 1723337, 'Texas': 695662,
'California': 423967}, name='area')
population = pd.Series({'California': 38332521, 'Texas': 26448193,
'New York': 19651127}, name='population')
print(population / area)#用人口除以面积会得到这样的结果(即使顺序不同,也会根据行索引名来除)
#结果数组的索引是两个输入数组索引的并集,对于缺失位置的数据,Pd会用NaN填充,
A = pd.Series([2, 4, 6], index=[0, 1, 2])
B = pd.Series([1, 3, 5], index=[1, 2, 3])
print(A+B)
#如果不想用NAN的结果,可以用适当的对象方法代替运算符:
print(A.add(B, fill_value=0))#A.add(B)等价于A + B,fill_value为自定义A或B缺失数据的填充
print("DataFrame索引对齐")
#在计算两个DataFrame 时,索引对齐规则也同样会出现在共同(并集)列中
A = pd.DataFrame(rng.randint(0, 20, (2, 2)), columns=list('AB'))
B = pd.DataFrame(rng.randint(0, 10, (3, 3)), columns=list('BAC'))
print(A+B)#结果的索引会自动按顺序排列
#用A中所有值的均值来填充缺失值
fill = A.stack().mean()#计算A 的均值需要用stack 将二维数组压缩成一维数组
print(A.add(B, fill_value=fill))
"""
需要插入参数的时候可以用oandas方法替代运算符:
表3-1:Python运算符与Pandas方法的映射关系
Python运算符 Pandas方法
+ add()
- sub()、subtract()
* mul()、multiply()
/ truediv()、div()、divide()
// floordiv()
% mod()
** pow()
"""
print("\n通用函数:DataFrame与Series的运算")
A = rng.randint(10, size=(3, 4))
print(A)
print(A - A[0])#根据np数组的广播规则进行运算,会按行计算
df = pd.DataFrame(A, columns=list('QRST'))
print("\nPandas运算:\n",df - df.iloc[0])#在Pandas 里默认也是按行运算的
#如果你想按列计算,那么就需要利用前面介绍过的运算符方法,通过axis 参数设置:
a=df.subtract(df['R'], axis=0)
print("\n按列计算:\n",a)
print(df.iloc[0, ::2])#series对象
print(df - df.iloc[0, ::2])
#行列保留和对齐是pandas的优势
print("\n处理缺失值")
"""大多数语言处理缺失数据是有两种方法:一种方法是通过一个覆盖全局的掩码表示缺失值,
另一种方法是用一个标签值(sentinel value)表示缺失值;
Pandas 最终选择用标签方法表示缺失值,包括两种Python 原有的缺失值:浮点数据类型的NaN 值,
以及Python 的None 对象。------关于缺失值详解参考P106"""
print("None:Python对象类型的缺失值")
#none是一个Py单体对象,经常在代码中表示缺失值。它是一个py的对象所以不能作为任何np\pd数组的缺失值
vals1 = np.array([1, None, 3, 4])
print(vals1)#ipython out:array([1, None, 3, 4], dtype=object),
"""这里dtype=object 表示NumPy 认为由于这个数组是Python 对象构成的,对数据的任何操作
最终都会在Python 层面完成,这种类型比其他原生类型数组要消耗更多的资源(时间)。"""
# vals1.sum()使用Python对象构成的数组进行累计操作时sum() 或者min(),会出现类型错误,
# Python 中没有定义整数与None 之间的加法运算。
print("\nNaN:数值类型的缺失值")
vals2 = np.array([1, np.nan, 3, 4])
print(vals2.dtype)#np为其选择数据类型为float64,这个数组会被编译成C代码从而实现快速操作
#可以把NaN看作是一个数据类病毒——它会将与它接触过的数据同化。无论和NaN进行何种操作,最终结果都是NaN
#很多情况下需要与nan运算时,结果是nan是不合理的 例如sum()运算时。
print(vals2.sum(), vals2.min