Panads是基于NumPy的一种工具,该工具是为了解决数据分析任务而创建的,其纳入了大量库和一些标准的数据模型,提供了高效地操作大型数据集所需的工具,Panads的数据类型包含Series、DataFrame和Panel.
本文主要介绍Series和DataFrame类型的基本使用方法。
import numpy as np
import pandas as pd
from pandas import Series,DataFrame
一、Series:一种类似于一维数组的对象,由values(一组ndarray类型的数据)和index(相关的数据索引标签)组成
Series创建
- Series(data=None, index=None, dtype=None, name=None, copy=False, fastpath=False)
1 由列表创建
s = Series([1,2,3])
s.index = list("abc") # 默认自动创建索引,可以通过设置index参数指定索引
s.index[0] = ["x"]
2 由numpy数组创建
s = Series(np.array([1,2,3])) # 由ndarray创建的是引用,而不是副本。对Series元素的改变也会改变原来的ndarray对象中的元素。(列表没有这种情况)
3 由字典创建
#当索引没有对应值时,缺失数据会显示NaN(not a number)
s = Series({'a':1, "b":2, "c":3}, index = ["a","b","c","d"])
'''
a 1
b 2
c 3
d NaN
dtype: float64
'''
查看数据
- shape ndarray属性,详见另一篇NumPy
- size
- dtype
- index
- head(Python method, in pandas.Series.head) 查看框架顶部的视图(默认查看前五条数据)
s.head(2) # 默认为5
'''
a 1.0
b 2.0
'''
- tail(Python method, in pandas.Series.tail) 查看框架底部的视图(默认查看后五条数据)
- values 查看NumPy底层数据
- describe(Python method, in pandas.Series.describe) 查看描述性统计
选择数据
1 索引:使用中括号取单个索引(返回值为元素类型),使用两个中括号取多个索引(返回值为Series类型)
1) 显示索引
- 使用index中的元素作为索引值
s['a'] # 1
s[['a']] # a 1
s[['a','c']]
'''
a 1
c 3
'''
- 使用.loc[] (推荐)
s.loc["a"]
s.loc[["a"]]
2) 隐式索引:
- 使用整数作为索引值
s[0]
- 使用.iloc[] (推荐)
s.iloc[0]
s.iloc[[0]]
s.iloc[[1,2]]
3) 层次化索引
- 隐式构造:最常见的方法是给构造函数的index参数传递两个或更多的数组
s_index = Series([1,2,3,'4'],index = [["a","a","b","b"],["a.a","b.b","a.a","b.b"]] )
'''
a a.a 1
b.b 2
b a.a 3
b.b 4
'''
- 显示构造:见DataFrame
2 切片:loc 都是左闭右闭 iloc都是左闭右开
s["a":"g"] # 左闭右闭
s.loc["a":"g"] # 左闭右闭
s.iloc[0:2] # 左闭右开
3 访问元素
- 访问多层索引对象
s_index['a'] # Series对象
'''
a.a 1
b.b 2
'''
s_index['a'][['a.a']] # Series对象
s_index['a','a.a'] # int类型,同s_index[0]和s_index['a']['a.a']
s_index[['a','a.a']] # Series对象
'''
a a.a 1
b.b 2
'''
Series运算
1 使用算术运算符
s2=Series([4,5,6])
s3=s+s2
'''
a NaN
b NaN
c NaN
d NaN
0 NaN
1 NaN
2 NaN
'''
2 使用通用函数(要保留所有的index,则需要使用这种方法)
- add(other,level=None,fill_value=None,axis=0)
s3=s.add(s2,fill_value=1)
'''
a 2.0
b 3.0
c 4.0
d NaN
0 5.0
1 6.0
2 7.0
'''
- sub(other,level=None,fill_value=None,axis=0)
- mul(other,level=None,fill_value=None,axis=0)
- div(other,level=None,fill_value=None,axis=0)
- std(axis=None, skipna=None, level=None, ddof=1, numeric_only=None, **kwargs) 计算标准差
- where(cond,other=nan,inplace=False,axis=None,level=None,error='raise',try_cast=False,raise_on_error=None) 按条件进行筛选
计数统计
- value_counts(normalize=False, sort=True, ascending=False, bins=None, dropna=True) 返回对象包含惟一值的计数
- sum(axis=None, skipna=None, level=None, numeric_only=None, min_count=0, **kwargs) 返回所请求的轴的值的总和
排序:这里的排序用的都是快速排序
- np.sort() 不改变输入
- ndarray.sort() 本地处理,不占用空间,但改变输入
- np.partition(a,k) a是要排序的ndarray, k为正时,得到最小的k个数;k为负时,得到最大的k个数
- np.argsort(nd[::,2]) 取nd的第三列数据
- argsort() 对索引进行排序
二、DataFrame:一种表格型数据结构,可以看做是由Series组成的字典(共用同一个索引)。DataFrame由按一定顺序排列的多列数据组成,设计初衷是将Series的使用场景从一维拓展到多维。DataFrame既有行索引(index),也有列索引(columns),其值(values)是numpy的二维数组。
DataFrame创建
- DataFrame(data=None, index=None, columns=None, dtype=None, copy=False)
1 由列表创建
df=DataFrame([1,2,3])
2 由numpy数组创建
df = DataFrame(np.array([1,2,3]))
3 由字典创建
df = DataFrame({'a':['a1','a2'],'b':['b1','b2'],'c':['c1','c2']},index=['a','b'])
注意:当行索引没有对应值时会报错,当列没有对应值时缺失数据会显示NaN(not a number)
查看数据:在Series基础上增加了columns属性
- columns 查看列名
df = DataFrame(data = np.random.randint(0,150,size= (4,4)),index = list("abcd"), columns = ["Python","Java","PHP","Html"])
'''
Python Java PHP Html
a 96 139 75 126
b 42 138 114 76
c 15 105 19 129
d 72 104 98 38
'''
选择数据
1 索引
1) 对列进行索引
- 使用类似字典的方式
df['Python'] # Series类型
'''
a 96
b 42
c 15
d 72
'''
df2[["Python","Java"]] # DataFrame类型
'''
Python Java
a 107 2
b 133 82
c 30 104
d 7 20
'''
- 使用属性的方式
df.Python
2) 对行进行索引:进行行索引时不能使用中括号
- 使用.ix[]进行行索引,现已弃用
df.ix['a'] # Series类型
df.ix[0]
'''
Python 96
Java 139
PHP 75
Html 126
'''
- 使用.loc[]加index进行行索引
df.loc['b'] # Series类型
df.loc[['b']] # DataFrame类型
- 使用.iloc[]加整数进行行索引
df.iloc[2] # Series类型
df.iloc[['2']] # DataFrame类型
3) 层次化索引
--1 创建多层行索引:
--1.1 隐式构造:最常见的方法是给构造函数的index参数传递两个或更多的数
#两层行索引
df_index = DataFrame([1,2,3,'4'],index = [["a","a","b","b"],["a.a","a.a","b.b","b.b"]],columns = ["Python"] )
#三层行索引
df_index = DataFrame(np.random.randint(0,150,size = 8),
index = [["a","a","a","a","b","b","b","b"],
["a.a","a.a","b.b","b.b","a.a","a.a","b.b","b.b"],
["a.a.a","b.b.b","a.a.a","b.b.b","a.a.a","b.b.b","a.a.a","b.b.b"]],
columns = ["Python"])
'''
Python
a a.a a.a.a 141
b.b.b 75
b.b a.a.a 50
b.b.b 103
b a.a a.a.a 65
b.b.b 124
b.b a.a.a 54
b.b.b 139
'''
--1.2 显示构造 pd.MultiIndex
- pd.MultiIndex.from_arrays(arrays,sortorder=None,names=None) 使用数组
df_index_from_arrays = DataFrame(data = np.random.randint(0,150,size = 8),
index = pd.MultiIndex.from_arrays([["a","a","a","a","b","b","b","b"],
["a.a","a.a","b.b","b.b","a.a","a.a","b.b","b.b"],
["a.a.a","b.b.b","a.a.a","b.b.b","a.a.a","b.b.b","a.a.a","b.b.b"]]),
columns = ["Python"])
- pd.MultiIndex.from_tuples(tuples,sortorder=None,names=None) 使用元组
df_index_from_tuples = DataFrame(np.random.randint(0,50,size = 4),
index = pd.MultiIndex.from_tuples([("a",'a.1'),("a",'a.2'),("b",'b.1'),("b",'b.2')]),
columns = ["Python"])
- pd.MultiIndex.from_product(iterables, sortorder=None, names=None) 使用product(推荐)
df_index_from_product = DataFrame(np.random.randint(0,50,size =4),
index = pd.MultiIndex.from_product([list("ab"), ["a.a","b.b"]]),
columns = ["Python"])
--2创建多层列索引:只需将index和columns参数互换,并重新调整size即可
df_index_from_product_col = DataFrame(np.random.randint(0,50,size =(1,4)),
columns = pd.MultiIndex.from_product([list("ab"), ["a.a","b.b"]]),
index = ["Python"])
'''
a b
a.a b.b a.a b.b
Python 43 14 26 0
'''
2 切片:只能对行进行切片,列不能进行切片
df.loc["a":"b"] # 左闭右闭
df.iloc[0:3] # 左闭右开
访问元素
1 访问单个元素
- at(Python attribute, in pandas.Series.at) 访问单个值
df.at['a','PHP']
- iat (Python attribute, in pandas.Series.iat) 使用整数来访问单个值
df.iat[1, 2]
- loc/ilco/索引
df.loc["a"]["Python"]
df.loc["a","Python"]
df["Python"]["a"]
#以下是错误演示,会导致KeyError
df['a']['Python']
df['a','Python']
df["Python","a"]
df.loc['python','a']
#总结:index和columns最好分开,先搜索index时需要加上loc[]
2 访问多个元素
- loc/ilco/索引
#先取列后切片
df["Java"]["a":"c"]
df["Java"].loc["a":"c"]
df['Java'].iloc[0:2]
#先切片后取列
df.loc["a":"b"]["PHP"]
df.loc["a":"b", "Python"]
df.loc[["a","b"]][["Python","Java"]] # DataFrame类型
注意:使用中括号时,索引表示的是列索引,切片表示的是行切片。
3 访问多层索引对象
- 直接使用列名称来进行列索引
- 进行行索引需要用ix(),loc()等函数
df_index_from_product['Python']['a','a.a']
df_index_from_product.loc['a','a.a']['Python'] # 先取行索引时要使用函数
4 索引的堆(stack)
- stack(level=-1, dropna=True) 将列索引堆到行索引上
df_index_from_product_col.stack()
'''
a b
Python a.a 27 11
b.b 18 23
'''
df_index_from_product_col.stack(level=0)
'''
a.a b.b
Python a 27 18
b 11 23
'''
- unstack(level=-1, fill_value=None) 将行索引堆到列索引上
df_index_from_product.unstack()
'''
Python
a.a b.b
a 44 29
b 1 5
'''
df_index_from_product.unstack(level=0)
'''
Python
a b
a.a 44 1
b.b 29 5
'''
拼接操作
# 定义一个生成DataFrame的函数
def make_df(cols, inds):
data = {c:[c+ str(i) for i in inds]for c in cols}
return DataFrame(data, index = inds)
1 级联
- pd.concat(objs, axis=0, join='outer', join_axes=None, ignore_index=False,keys=None, levels=None, names=None, verify_integrity=False,copy=True) 使用与np.concatenate类似,ignore_index:忽略index使用默认索引(index在级联时可以重复),keys:使用多层索引,join:连接模式,join_axes:连接指定轴
- append(other,ignore_index=False,verify_intergrity=False,sort=None) 追加
1) 匹配级联:优先增加行数,可以通过设置axis来改变级联方向
2) 不匹配级联:级联的维度的索引不一致。例如纵向级联时列索引不一致,横向级联时行索引不一致
df1 = make_df(list("abc"), [1,2,3])
df2 = make_df(list("abcd"), [3,4,5,6])
df3 = make_df(list("abcz"), [3,4,7,8])
pd.concat([df1,df2],join='inner') # join='outer' 外连接:补NaN(默认模式); inner 内连接:只连接匹配的项
pd.concat([df1,df3],join_axes=[df3.columns]) # join_axes选取轴面,参数为列表或索引对象
2 合并:必须要有相同的属性
- merge(right, how='inner', on=None, left_on=None, right_on=None, left_index=False, right_index=False, sort=False, suffixes=('_x', '_y'), copy=True, indicator=False, validate=None) 使用merge合并时,会根据两者相同column作为key来合并(每一列元素的顺序不要求一致),
- on:显式指定哪一列为key(当有多个key相同时使用)
- left_on/right_on:指定左右两边的列作为key(当左右两边的key都不想等时使用)
- how:合并选项[inner:内合并,只保留两者都有的key(默认模式);outer:外合并,补NaN;left:左连接,使用类似SQL;right:右连接]
- suffixes:指定冲突列名(当列冲突时,即有多个列名称相同时,需要使用on来指定key,suffixes指定冲突的列名)
- join(other, on=None, how='left', lsuffix='', rsuffix='', sort=False)
df_merge1 = DataFrame({"age":[10,20,30],"work":["tech","accounting","sell"],"sex":['男',"女","女"]},index = list("abc"))
df_merge2 = DataFrame({"home":["x","y","z"],"work":['tech',"accounting","sell"],"weight":[60,50,40]}, index = list("abc"))
df_merge3 = DataFrame({"home":["x","y","z","c","i"],'work':["tech","tech","tech","accounting","sell"],"weight":[60,70,80,90,100]}, index = list("abcef"))
df_merge4 = DataFrame({"age":[20,30,40,50],"work":["tech","tech","accounting","sell"],"sex":["女","男","女","男"]}, index = list("abce"))
1) 一对一合并
df_merge1.merge(df_merge2)
'''
age sex work home weight
0 10 男 tech x 60
1 20 女 accounting y 50
2 30 女 sell z 40
'''
2) 多对一合并
df_merge1.merge(df_merge3)
'''
age sex work home weight
0 10 男 tech x 60
1 10 男 tech y 70
2 10 男 tech z 80
3 20 女 accounting c 90
4 30 女 sell i 100
'''
3) 多对多合并
df_merge4.merge(df_merge3)
'''
age sex work home weight
0 20 女 tech x 60
1 20 女 tech y 70
2 20 女 tech z 80
3 30 男 tech x 60
4 30 男 tech y 70
5 30 男 tech z 80
6 40 女 accounting c 90
7 50 男 sell i 100
'''
DataFrame运算
df2 = DataFrame({"Python":[99,101,120,78],
"C":[120,136,141,149],
"C++":[123,114,130,117]}, index = list("abcd"),)
1 Series与DataFrame之间的运算
-
使用Python操作符:以行为单位操作(参数必须是行),对所有行都有效。(类似于numpy中二维数组与一维数组的运算,但可能出现NaN)
-
使用pandas操作函数: axis=0:以列为单位操作(参数必须是列),对所有列都有效。 axis=1:以行为单位操作(参数必须是行),对所有行都有效。
-
操作行时列需要一致,操作列时行需要一致。在运算中自动对齐不同索引的数据,如果索引不对应,则补NaN,不能使用fill_value参数进行填充
df2_col=Series({'a':10,'b':20,'c':30,'d':40,'e':50})
df2.add(df2_col) # axis默认值为1
'''
C C++ Python a b c d e
a NaN NaN NaN NaN NaN NaN NaN NaN
b NaN NaN NaN NaN NaN NaN NaN NaN
c NaN NaN NaN NaN NaN NaN NaN NaN
d NaN NaN NaN NaN NaN NaN NaN NaN
e NaN NaN NaN NaN NaN NaN NaN NaN
'''
df2.add(df2_col,axis=0)
'''
C C++ Python
a 130.0 133.0 109.0
b 156.0 134.0 121.0
c 171.0 160.0 150.0
d 189.0 157.0 118.0
e 110.0 130.0 90.0
'''
2 DataFrame之间的运算:同Series
- 在运算中自动对齐不同索引的数据
- 如果索引不对应,则补NaN,可以使用fill_value参数进行填充
# 添加一行数据
df2=df2.add(DataFrame({"Python":40,'C':60,'C++':80},index=['e']),axis=1,fill_value=0)
'''
C C++ Python
a 120.0 123.0 99.0
b 136.0 114.0 101.0
c 141.0 130.0 120.0
d 149.0 117.0 78.0
e 60.0 80.0 40.0
'''
df.add(df2,fill_value=0) # 追加DataFrame
'''
C C++ Html Java PHP Python
a 120.0 123.0 23.0 70.0 130.0 172.0
b 136.0 114.0 17.0 21.0 119.0 132.0
c 141.0 130.0 2.0 113.0 117.0 185.0
d 149.0 117.0 98.0 71.0 144.0 118.0
e 60.0 80.0 NaN NaN NaN 40.0
'''
df2.where(df2>120,other=0) # 筛选
'''
C C++ Python
a 0 123 0
b 136 0 0
c 141 130 0
d 149 0 0
'''
df2.sum(axis=1) # 计数统计
'''
a 342
b 351
c 391
d 344
'''
df2['C'].value_counts()
'''
141 1
149 1
136 1
120 1
'''
df2.std() # 标准差
'''
C 12.233833
C++ 7.071068
Python 17.175564
'''
数据筛选
- 条件筛选
df2[df2.C>140]
'''
C C++ Python
c 141 130 120
d 149 117 78
'''
- 使用&符号进行多条件筛选
df2[(df2.C>140)&(df2.Python<100)]
- 使用|符号进行多条件筛选
df2[(df2.C>140)|(df2.Python<100)]
- isin(values) 筛选特定的值,values类型可以为iterable, Series, DataFrame 或 dictionary
df2.isin([120,117])
'''
C C++ Python
a True False False
b False False False
c False False True
d False True False
'''
数据分组
- groupby(by=None, axis=0, level=None, as_index=True, sort=True, group_keys=True, squeeze=False, observed=False, **kwargs) 数据分组
- aggregate(func, axis=0, *args, **kwargs) 数据分组计算
- size() 查看各组数据量
- describe() 对各组数据进行描述性统计
- agg() 分组多种计算
缺失值处理
1 先介绍下两种缺失值 :None,np.nan(NaN)
- Python中的None类型为python object(ndarray里的None是python对象),不能参与到任何计算中;np.nan是浮点类型,能参与到计算中,但计算的结果总是NaN
nd = np.array([10,20,30,np.nan])
# 可以使用np.nan*()函数来计算包含nan的值,此时视nan为0。
np.nansum(nd) # 75.0
nd = np.array([10,20,45,np.nan, None])
nd.sum() # TypeError
- Panads中的None和np.nan都视作np.nan
df3 = DataFrame([10,20,30,None,np.nan], index = list('abcde'), columns = ["Python"])
df3.sum() # Python 60.0
2 对缺失值进行处理
- isnull()/notnull() 检测缺失数据
df.isnull() # 返回的是boolean,如果为空显示true,不为空显示false,notnull()则相反
# isnull和any连用时可以判断哪一列或者哪一行有空值 notnull需要与all连用
df_isnull = df.isnull.any(axis=1) # Series类型
df[df_isnull] #可以根据条件过滤掉不为空的值,留下有空的值
- fillna(value=None, method=None, axis=None, inplace=False, limit=None, downcast=None, **kwargs) 用固定数替代缺失值
df.fillna(1) # 用1填充NaN
# fillna的method参数包含{'backfill', 'bfill', 'pad', 'ffill', None},默认值为None 对于DataFrame来说,还要选择填充的轴axis
df.fillna(method='ffill') # 向前填充
df.fillna(method='bfill') # 向后填充
- 用统计值替代缺失值
#也可以使用平均数或者其他描述性统计量来代替NaN
df.fillna(df.mean())
- interpolate(method='linear', axis=0, limit=None, inplace=False, limit_direction='forward', downcast=None, **kwargs) 用插值法填补缺失值
- dropna(axis=0, how='any', thresh=None, subset=None, inplace=False) 删除缺失值
- replace(to_replace=None, value=None, inplace=False, limit=None, regex=False, method='pad', axis=None) 替换缺失值
数据处理
1 删除重复元素
- duplicated(subset=None, keep='first') 检测重复的行,返回元素为布尔类型的Series对象,每个元素对应一行,如果该行不是第一次出现,则元素为True
- drop_duplicates(subset=None, keep='first', inplace=False) 删除重复行
2 映射
- replace(to_replace=None, value=None, inplace=False, limit=None, regex=False, method='pad') 替换元素
- map(arg, na_action=None) 新建一列(由已有的列生成一个新列,适合处理某一单独的列)
- rename(mapper=None, index=None, columns=None, axis=None, copy=True, inplace=False, level=None) 替换索引
3 异常值检测和过滤
4 排序
- take(indices, axis=0, convert=None, is_copy=True, **kwargs) 返回给定位置索引中的元素。
index = np.random.permutation(4) # array([0, 3, 1, 2])
df2.take(index)
'''
C C++ Python
a 120 123 99
d 149 117 78
b 136 114 101
c 141 130 120
'''
5 数据聚合:数据聚合是数据处理的最后一步,通常是要使每一个数组生成一个单一的数值。
- 分组:先把数据分为几组
- 用函数处理:为不同组的数据应用不同的函数以转换数据
- 合并:把不同组得到的结果合并起来
6 高级数据聚合
- transform(func, *args, **kwargs) 调用函数产生一个同索引的NDFrame并返回一个带有转换值的NDFrame。使用与map()类似,区别是transform()可以传系统函数,map()不可以.
- apply(func, axis=0, broadcast=None, raw=False, reduce=None, result_type=None, args=(), **kwds) 在DataFrame轴上应用一个函数
读取文件
- pandas.read_clipboard (Python function, in pandas.read_clipboard)
- pandas.read_csv (Python function, in pandas.read_csv)
- pandas.read_excel (Python function, in pandas.read_excel)
- pandas.read_feather (Python function, in pandas.read_feather)
- pandas.read_fwf (Python function, in pandas.read_fwf)
- pandas.read_gbq (Python function, in pandas.read_gbq)
- pandas.read_hdf (Python function, in pandas.read_hdf)
- pandas.read_html (Python function, in pandas.read_html)
- pandas.read_json (Python function, in pandas.read_json)
- pandas.read_msgpack (Python function, in pandas.read_msgpack)
- pandas.read_parquet (Python function, in pandas.read_parquet)
- pandas.read_pickle (Python function, in pandas.read_pickle)
- pandas.read_sas (Python function, in pandas.read_sas)
- pandas.read_sql (Python function, in pandas.read_sql)
- pandas.read_sql_query (Python function, in pandas.read_sql_query)
- pandas.read_sql_table (Python function, in pandas.read_sql_table)
- pandas.read_stata (Python function, in pandas.read_stata)
- pandas.read_table (Python function, in pandas.read_table)
x = pd.read_csv("xxx.csv",encoding='gbk')
可视化
- plot(kind='line', ax=None, figsize=None, use_index=True, title=None, grid=None, legend=False, style=None, logx=False, logy=False, loglog=False, xticks=None, yticks=None, xlim=None, ylim=None, rot=None, fontsize=None, colormap=None, table=False, yerr=None, xerr=None, label=None, secondary_y=False, **kwds)
- kind='line' 折线图(默认模式)
- kind='scatter' 散点图
- kind='bar/barh' 柱状图
- kind = 'kde' 百分比密度图
s=Series(np.random.randint(0,10,10))
s.plot()
df = DataFrame(np.random.randint(0,10,size = (10,4)), columns = list('ABCD'))
df.plot(kind='kde')
- hist(column=None, by=None, grid=True, xlabelsize=None, xrot=None, ylabelsize=None, yrot=None, ax=None, sharex=False, sharey=False, figsize=None, layout=None, bins=10, **kwds) 直方图
- 使用hist()函数时,必须添加属性normed = True,将数据进行归一化0-1之间的数据
normal1 = np.random.normal(0,1,size = 200)
normal2 = np.random.normal(10,2,size = 200)
norm = np.concatenate([normal1, normal2])
s = Series(norm)
s.hist(bins = 200, normed = True)
s.plot(kind = "kde",color = "red",style = "-.")
- boxplot(column=None, by=None, ax=None, fontsize=None, rot=0, grid=True, figsize=None, layout=None, return_type=None, **kwds) 箱型图
广播:一个矩阵或向量减去一个常数,那么通常是矩阵中的每一个元素减去这个常量。
数据库操作
- read_sql() 从数据库中读取数据
- index_col() 规定将哪一列数据设置为index(可以通过将index_col的值设置为列表来设置多个index)
- write_sql() 将数据保存到数据库中