NumPy
pandas <<=
数据可视化
Pandas是基于NumPy数组构建的,特别是基于数组的函数和不适用for循环的数据处理,二者最大的不同是,Pandas是专门为处理表格和混杂数据设计的,而NumPy更适合处理统一的数值数组的数据。
Pandas是个比较的库了,第二版里边大约是根据ETL的方式在组织着,并且举了更多的例子,由于篇幅太大,很适用。这里将Pandas分成2篇,一篇基础,包括数据类型、索引、存储与加载,另外一篇是进阶,包括清理、转换、聚合
pandas的数据结构
Series
-
基本属性与创建
Series 是一维带标记的数组结构,可以存储任意类型的数据(整数,浮点数,字符串,Python 对象等等)。
Series有2个属性,一是数据的values,它是一维的数组;二是数据的index,它代表着数据的索引
obj = pd.Series([4, 7, -3, 6])
obj.values # array([4, 7, -3, 6])
obj.index # RangeIndex(start=0, stop=4, step=1)
创建时,可以通过index指明索引:
obj2 = pd.Series([4, 7, -5, 3], index=['d', 'b', 'a', 'c'])
obj2.index # Index(['d', 'b', 'a', 'c'], dtype='object')
如果 data 是个 ndarray,那么 index 的长度必须跟 data 一致
如果 index 为空,那么 index 会使用 [0, ..., len(data) - 1]:
除了通过列表创建,Series还可以通过字典创建。如果 data 是个 dict,如果不给定 index,那么 index 将使用 dict 的 key 排序之后的结果
sdata = {'Ohio': 35000, 'Texas': 71000, 'Oregon': 16000, 'Utah': 5000}
obj3 = pd.Series(sdata)
obj3
# Ohio 35000
# Oregon 16000
# Texas 71000
# Utah 5000
states = ['California', 'Ohio', 'Oregon', 'Texas']
obj4 = pd.Series(sdata, index=states)
obj4
# California NaN
# Ohio 35000
# Oregon 16000
# Texas 71000
Series对象本身以及index都有一个name属性,如
obj4.name = 'population'
obj4.index.name = 'state'
Series的索引可以通过赋值的方式就地修改
obj.index = ['Bob', 'Steve', 'Jeff', 'Ryan']
-
基本使用
Series跟NumPy的array的使用方式有些类似
obj2['a'] # -5
obj2['d'] = 6
obj2[['c','a','d']]
# c 3
# a -5
# d 6
obj2[obj2 > 0]
# d 6
# b 7
# c 3
obj2*2
# d 12
# b 14
# a -10
# c 6
np.exp(obj2)
'b' in obj2
#True
Seriesd对于缺省数据,可以通过isnull和notnull进行检查
pd.isnull(obj4)
pd.notnull(obj4)
与np的array不同,Series进行计算时,会根据索引标签自动对齐数据,这一点类似于sql的join功能
obj3+obj4
# California NaN
# Ohio 70000.0
# Oregon 32000.0
# Texas 142000.0
# Utah NaN
DataFrame
DataFrame是Pandas的灵魂,如果把Series看成一维的,那它就是二维的,对照Series,它有3个基本属性:数据的values,数据的行索引index,数据的列索引column。可以通过frame.columns、frame.index等访问
-
创建
DataFrame(data, index, columns) 中的 data 可以接受很多数据类型,如Numpy数组组成的字典、2维ndarray、另外一个DataFrame
从 ndarray 或者 list 字典中构造
data = {'state': ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada', 'Nevada'],
'year': [2000, 2001, 2002, 2001, 2002, 2003],
'pop': [1.5, 1.7, 3.6, 2.4, 2.9, 3.2]}
frame = pd.DataFrame(data, index=['one', 'two', 'three', 'four', 'five', 'six'])
二维数据
arrData = np.random.randn(2,3)
df = pd.DataFrame(arrData, index=['a','b'], columns=['job','position'])
-
基本使用
frame.head() # 对于特别大的DataFrame,head方法会取前5行
frame['state'] # 这种取法,是取的'state'列与index
frame.state # 同上
frame.loc['one'] # 这种取法,取的是'one'这一行以及column
frame.iloc[0] # 这是是通过下标进行获取的
frame.loc['one', 'state'] # loc可以放行列2个值
frame['debt'] = np.arange(6) # 这样是增加一个'debt'列,并赋值
frame['eastern'] = fram.state == 'Ohio' # 增加一个'eastern'列, 当'state' 为'Ohio'是True,否则为False
del frame['eastern'] # 删除该列
基本功能
reindex
它的作用是创建一个新对象,数据符合新的索引,若没有,则用NaN填充。对Series与DataFrame都适用。
别被它的名字所骗,它本质上是一个复制操作
obj = pd.Series([4.5, 7.2, -5.3, 3.6], index=['d','b','a','c'])
obj2 = obj.reindex(['a', 'b', 'c', 'd', 'e'])
# a -5.3
# b 7.2
# c 3.6
# d 4.5
# e NaN
对于时间序列这样的有序数据,reindex时候,可以做一些插值处理。
obj3 = pd.Series(['blue', 'purple', 'yellow'], index=[0, 2, 4])
obj3.reindex(range(6), method='ffill')
注意:无序数据是不能用ffill的
对于DataFrame,reindex既可以修改index,也可以修改column
frame = pd.DataFrame(np.arange(9).reshape((3, 3)), index=['a', 'c', 'd'], columns=['Ohio', 'Texas', 'California'])
frame2 = frame.reindex(['a', 'b', 'c', 'd'])
frame3 = frame.reindex(columns=['Texas', 'Utah', 'California'])
drop
删除指定轴上的一个或多项,它返回的是一个删除之后的新对象
frame2.drop(['a', 'b']) # 删除,a,b两行
frame2.drop(['Texas', 'Utah'], axis=1) # 删除Texas,Utah两列
fill_value
在进行算术运算时候,如果reindx不匹配,就会出现NaN,这时候可以通过传入fill_value参数,来对NaN进行填充
df1 = pd.DataFrame(np.arange(12.).reshape((3, 4)), columns=list('abcd'))
df2 = pd.DataFrame(np.arange(20.).reshape((4, 5)), columns=list('abcde'))
df1 + df2
df1.add(df2, fill_value=0) # 这是,e就会有值,先对NaN填充成0,然后再计算
算术方法包括:
方法 | 说明 |
add、radd | 加法 |
sub、rsub | 减法 |
div、rdiv | 除法 |
mul、rmul | 乘法 |
pow、rpow | 指数 |
注意:r代表着参数反转
apply与applymap
NumPy的ufuncs也适用于操作pandas对象
frame = pd.DataFrame(np.random.randn(4, 3))
np.abs(frame)
另外将函数应用到由某行或者某列所形成的一维数组上,使用apply方法
f = lambda x: x.max() - x.min()
frame.apply(f) # 对每列执行(沿着axis=0)
frame.apply(f, axis='columns') # 对每行执行,或者是axis=1
对多常见的数组统计功能,都被实现成了DataFrame的方法,如sum、mean,无需使用apply。
元素级的函数也可以用在DataFrame中,使用applymap方法
format = lambda x: '%.2f' % x
frame.applymap(format)
sort与rank
sort有2种:sort_index与sort_value
frame = pd.DataFrame(np.arange(8).reshape((2, 4)), index=['three', 'one'], columns=['d', 'a', 'b', 'c'])
frame.sort_index()
frame.sort_index(axis=1, ascending=False) # 以columns来排序,降序
frame.sort_value(by='b') # 按b列的值进行排序
rank是为每组分配一个平均排名的方式
obj = pd.Series([7, -5, 6])
obj.rank() # 它给出的每个value的一种排名
汇总
与Numpy相同,Pandas也集成了一组常用的数据和统计方法。与Numpy不同的是,他们都是基于没有缺失数据的假设而创建的。
这些方法包括:
方法 | 说明 |
count | 非NA值的数量 |
describe | 汇总统计 |
min、max | 最值 |
argmin、argmax | 最值的索引位置 |
quantile | 计算样本的分位数(0-1) |
sum | 求和 |
mean | 平均 |
median | 中位数 |
var | 方差 |
std | 标准差 |
skew | 样本的偏度(三阶矩) |
kurt | 样本的峰度(四阶矩) |
cumsum | 累计和 |
cumprod | 累计积 |
diff | 一阶差分 |
pct_change | 百分数变化 |
corr | 相关系数 |
cov | 协方差矩阵 |
数据加载与存储
与Numpy相比,pandas对数据的输入输出更看重一些,也增加了对数据库的支持
这里介绍几个常用的:
函数 | 说明 |
read_csv | 从csv中读取 |
read_excel | 从excel中读取 |
read_json | 从json中读取 |
read_sql | 读取SQL查询结果 |
read_csv
! cat example.csv
a,b,c,d,message
1,2,3,4,hello
5,6,7,8,world
df = pd.read_csv('example.csv') # 这时候首行被认为是column,可以通过制定header =None来取消默认
df = pd.read_csv('example.csv', header=None)
通过to_csv方法,可以将数据导出到csv文件中
data.to_csv('data.csv')
大文件的处理
对于很大的文件,可以只读取几行数据,通过指定nrows
即可
df = pd.read_csv('example.csv', nrows=5) # 只读取5行
也可以逐块读取文件,通过指定chunksize
chunker = pd.read_csv('example.csv', chunksize=1000) # 这时候返回的是TextParse对象,可以迭代
tot = pd.Series([])
for piece in chunker:
tot = tot.add(piece['key'].value_counts(), fill_value=0) # value_counts就是每个value出现的count
tot =tot.sort_values()
read_json
!cat example.json
[{"a": 1, "b": 2, "c": 3},
{"a": 4, "b": 5, "c": 6},
{"a": 7, "b": 8, "c": 9}]
data = pd.read_json('example.json')
print(data.to_json()) # 与csv相同可以通过to_json()输出
read_excel
xlsx = pd.ExcelFile('ex1.xlsx')
data = pd.read_excel(xlsx, 'sheet1')
writer = pd.ExcelWriter('ex2.xlsx')
data.to_excel(writer, 'sheet1')
writer.save
read_sql
可以通过python读数据库的操作,将数据读取到,然后创建成DataFrame 。对这种方式不作介绍了
python sql项目SQLAlchemy可以对sql数据进行抽象,然后通过read_sql可以直接操作
import sqlalchemy as sqla
db = sqla.create_engine("sqlite://mydata.sqlite") # 这里数据库用的sqlite,其他数据库类似
data = pd.read_sql("select * from test", db)