Python数据分析之Pandas入门(上)
本系列共有三篇文章,依次按照pandas数据类型及其结构、内置模块对数据处理功能、可视化工具以及形如房价预测的案例分析内容展开介绍。本篇文章的代码均已测试通过,参考自书籍《Python for Data Analysis(Second Edition)》
目录
前言
本系列共有三篇文章,依次按照pandas数据类型及其结构、内置模块对数据处理功能、可视化工具以及形如房价预测的案例分析内容展开介绍。本篇文章的代码均已测试通过,参考自书籍《Python for Data Analysis(Second Edition)》。
Pandas 起初是作为金融数据分析工具被Wes McKinney开发出来的,其名称来源于面板数据(Panel Data)和Python 数据分析(Data Analysis),Panel Data 是经济学中关于多维数据集的一个术语;Pandas支持绝大部分NumPy风格的数组计算,不同的是,NumPy用于处理同质性的数值类型数组数据,而pandas是用来处理表格型或异质型数据的。
一、 数据结构
1.Series()
pandas.Series(data, index, dtype, name, copy)
将数据展开成带索引值的一列
参数说明:
data:一组数据(ndarray 类型)
index:数据索引标签,如果不指定,默认从 0 开始。
dtype:数据类型,默认会自己判断
name:设置Series类的某个实例名称
copy:拷贝数据,默认为 False
import pandas as pd
a = ['Alex', 'Bob', 'Clara']
my_var = pd.Series(a, index=[1, 2, 3])
sites = {1: "Google", 2: "Runoob", 3: "Wiki"}
myvar = pd.Series(sites, index = [1, 2], name="RUNOOB-Series-TEST" ) # 若只需要字典的部分值,则在索引值中指定范围
print(my_var, '\n')
print(myvar)
输出为:
1 Alex
2 Bob
3 Clara
dtype: object
1 Google
2 Runoob
Name: RUNOOB-Series-TEST, dtype: object
可以看到,pandas可接收列表和字典类型的数据作为Series类的创建对象,并能够按照序列进行索引,这样的切片操作可用于截取前num_request人数的信息。
# 可以认为Series是一个长度固定且有序的字典
import pandas as pd
sdata = {'Ohio': 35000, 'Texas': 71000, 'Oregon': 16000, 'Utah': 5000}
obj = pd.Series(sdata)
print(obj)
# 将字典的值按理想的键值排序
states = ['California', 'Oregon', 'Texas', 'Ohio', 'Utah']
obj = pd.Series(sdata, index=states)
print('\n重新排序后的字典:\n', obj)
print('\n检查缺失的数据:\n', pd.isnull(obj)) # 还可以用'pd.notnull(obj)',isnull和notnull也是Series中的实例方法: obj.isnull
输出为:
Ohio 35000
Texas 71000
Oregon 16000
Utah 5000
dtype: int64
重新排序后的字典:
California NaN
Oregon 16000.0
Texas 71000.0
Ohio 35000.0
Utah 5000.0
dtype: float64
检查缺失的数据:
California True
Oregon False
Texas False
Ohio False
Utah False
dtype: bool
2.DataFrame()
pandas.DataFrame( data, index, columns, dtype, copy)
DataFrame 是一个矩阵的数据表,它含有一组有序的列,每列可以是不同的值类型(数值、字符串、布尔值等)。DataFrame 既有行索引也有列索引,它可以被看做由 Series 组成的字典(共同用一个索引),可用分层索引展现更高维度的数据。
参数说明:
data:一组数据(ndarray、series, map, lists, dict 等类型)
index:索引值,或者可以称为行标签
columns:列标签,默认为 RangeIndex (0, 1, 2, …, n)
dtype:数据类型
copy:拷贝数据,默认为 False
从DataFrame中选区的列是数据的视图,而不是拷贝。对Series的修改会映射到DataFrame中去
①基本构造及属性
类型 | 注释 |
---|---|
2D ndarray | 数据的矩阵,行和列的标签是可选的参数 |
数组、列表和元组构成的字典 | 每个序列成为DataFrame的一列,所有的序列必须长度相等 |
NumPy结构化/记录化数组 | 与数组构成的字典一致 |
Series构成的字典 | 每个值成为一列,每个Series的索引联合起来形成结果的行索引,也可以显式地传递索引 |
字典构成的字典 | 每一个内部字典成为一列,键联合起来形成结果的行索引 |
字典或Series构成的列表 | 列表中的一个元素形成DataFrame的一行,字典键或Series索引联合起来形成DataFrame的列标签 |
列表或元组构成的列表 | 与2D ndarray的情况一致 |
其他DataFrame | 如果不显示传递索引,则会使用原DataFrame的索引 |
NumPy MaskeArray | 与2D ndarray的情况类似,但隐藏值会在结果DataFrame中成为NA/缺失值 |
- 利用二维数组创建DataFrame
import pandas as pd
data = [['Google',1],['Baidu',2],['Wiki',3]]
df = pd.DataFrame(data,columns=['Site','Age'] ) # 给每一列添上标签
print(df)
(自动生成索引)输出为:
Site Age
0 Google 1
1 Baidu 2
2 Wiki 3
- 利用多个同等长度的列表或NumPy数组组成的字典形成 DataFrame
import pandas as pd
data = {'name': ['Alex', 'Bob', 'Charlie', 'Dave', 'Emily'],
'birth': [2001, 2000, 1989, 2001, 2003],
'score': [96., 97.8, 99, 94., 90.3]}
frame = pd.DataFrame(data)
print(frame)
print('\n重新排序过的表格:\n', pd.DataFrame(data, columns=['name', 'score', 'birth']))
frame2 = pd.DataFrame(data, columns=['name', 'score', 'birth', 'gender'], index=['one', 'two', 'three', 'four', 'five'])
print('\n未初始化键值的指定列下会出现缺失值:\n',frame2)
# 可以按字典型标记或属性那样检索为:Series
print('\n检索姓名:\n', frame2['name'])
print('\n检索分数:\n', frame2.score)
# 通过位置或特殊属性进行选取
print('\n位置\'three\'索引:\n', frame2.loc['three'])
# 如果将Series赋值给一列时,Series的索引将会按照DataFrame的索引重新排列,并在空缺的地方填充缺失值
val = pd.Series(['F', 'M', 'M'], index=['five', 'one', 'two'])
frame2['gender'] = val
print('\n补充上空缺值后:\n', frame2)
del frame2['birth']
print('\n删除生日一列后:\n', frame2)
②索引对象
方法 | 描述 |
---|---|
append | 将额外的索引对象粘贴到原数据结构中后,产生一个新的索引 |
diffarance | 计算两索引的差集 |
intersection | 计算两索引的交集 |
union | 计算两索引的并集 |
isin | 计算表示每一个值是否在传值容器中的布尔数组 |
delete | 将位置i的元素删除,并产生新的索引 |
drop | 根据传参删除指定索引值,并产生新的索引 |
insert | 在位置i插入元素,并产生新的索引 |
is_monotonic | 如果索引序列递增的话返回True |
is_unique | 如果索引序列惟一的话返回True |
unique | 计算索引的唯一值序列 |
import pandas as pd
import numpy as np
obj = pd.Series(range(3), index=['a', 'b', 'c'])
index = obj.index
print(index[1:])
# 索引对象不可变,因此用户不可修改;但根据索引对象可以修改对应的值
# 不变性使得在多种数据结构中分享索引对象更安全
labels = pd.Index(np.arange(3))
obj1 = pd.Series([1.5, -1, 0], index=labels)
print("labels is obj1.index: ", labels is obj1.index)
# 与Python集合不同,pandas索引可以包含重复标签
dup_labels = pd.Index(['Apple', 'Banana', 'Apple', 'Pear'])
print(dup_labels)
3.Panel()
pandas.Panel(data=None, items=None, major_axis=None, minor_axis=None, copy=False, dtype=None)
pandas.Panel()
represents wide format panel data, stored as 3-dimensional array
参数说明:
data : ndarray (items x major x minor), or dict of DataFrames
tems : Index or array-like
axis=0
major_axis : Index or array-like
axis=1
minor_axis : Index or array-like
axis=2dtype : dtype, default None
Data type to force, otherwise infer
copy : boolean, default False
Copy data from inputs. Only affects DataFrame / 2d ndarray input
- 详见官方文档示例
二、基本功能
1.重建索引
obj.reindex(index, method, fill_value, limit, tolerance, level, copy)
用于创建一个个符合新索引的新对象。
参数说明如下:
index: 新建作为索引的序列,可以是索引实例或任意其他序列型Python数据结构,索引使用时无需复制
method: 插值方式,'ffill’为前向填充,'bfill’是后向填充
limit: 当前向或后向填充时,所需填充的最大尺寸间隙(以元素数量)
tolerance: 当前向或后向填充时,所需填充的不精确匹配下的最大尺寸间隙(以绝对数字距离)
level: 匹配MultiIndex级别的简单索引;否则选择子集
copy: 如果为True,即使新索引等于旧索引,也总是复制底层数据;如果是False,则在索引相同时不要复制数据
import pandas as pd
obj = pd.Series([4.5, 7.2, -5.3, 3.6], index=['d', 'b', 'a', 'c'])
obj2 = obj.reindex(['a', 'b', 'c', 'd', 'e'])
print("obj2按照新的顺序排列后:\n", obj2) # 即改变行索引
obj3 = pd.Series(['blue', 'purple', 'yellow'], index=[0, 2, 4])
print("\nobj3数据对象如下所示:\n", obj3)
print("\nobj3数据对象插值后如下所示:\n", obj3.reindex(range(6), method='ffill'))
# 既可以改变行索引,也可以改变列索引
obj3 = pd.DataFrame(np.arange(9).reshape((3, 3)), index=['a', 'c', 'd'], columns=['number', 'color', 'level'])
print("\nobj3数据对象重置后如下所示:\n", obj3)
frame = obj3.reindex(columns=['number', 'Like', 'color'])
print("\nobj3数据对象改变列索引后如下所示:\n", frame)
print("\nobj3数据对象改变行索引后如下所示:\n", obj3.reindex(['a', 'b', 'c', 'd']))
2.轴向上删除条目
drop()
方法会返回一个含有指示值或轴向上删除值的新对象
import pandas as pd
data = pd.DataFrame(np.arange(16).reshape((4, 4)),
index=['Ohio', 'Colorado', 'Utah', 'New York'],
columns=['one', 'two', 'three', 'four'])
print(data)
# 在调用drop时使用“标签序列”会根据行标签删除值(轴0)
print("\n调用drop方法删除之后:\n", data.drop(['Colorado', 'Ohio']))
print("\n沿轴1,即\'axis=1\'或\'axis=columns\':\n", data.drop('two', axis=1))
# 该方法都是直接在源对象上操作,而不返回新对象;📢注意:inplace会清除被删除的数据
data.drop(['New York'], inplace=True)
3.索引、选择与过滤
- 索引(详见1.2“索引对象”)
- 普通索引(键值索引)
- 切片索引
- 条件索引
- 选择(行标签索引)
.loc[]
.iloc()
- 过滤(索引+切片)
类型 | 描述 |
---|---|
df[val] | 从DataFrame中选择单列或列序列;特殊情况的便利:布尔数组(过滤行),切片(切片行)或布尔值DataFrame |
df.loc[val] | 根据标签选择DataFrame的单行或多行 |
df.loc[:, val] | 根据标签选择单列或多列 |
df.loc[val1, val2] | 同时选择行和列的一部分 |
df.iloc[where] | 根据整数位置选择单行或多行 |
df.iloc[:, where] | 根据整数位置选择单列或多列 |
df.iloc[where_i, where_j] | 根据整数位置选择行和列 |
df.at[label_i, label_j] | 根据行、列标签选择单个标量值 |
df.iat[i, j] | 根据行、列整数位置选择单个标量值 |
reindex方法 | 通过标签选择行或列 |
get_value, set_value | 根据行和列的标签设置单个值 |
import pandas as pd
import numpy as np
""" 索引 """
obj = pd.Series(np.arange(4.), index=['a', 'b', 'c', 'd'])
data = pd.DataFrame(np.arange(16).reshape((4, 4)),
index=['Ohio', 'Colorado', 'Utah', 'New York'],
columns=['one', 'two', 'three', 'four'])
# 普通的Python切片是不包含尾部的,但Series不一样
print(obj['b':'c'], '\n')
# 键值索引
print(data[['three', 'one']], '\n')
# 条件索引
print(data[data['three']>5], '\n')
""" 选择 """
print(data.loc['Colorado', ['two', 'three']], '\n')
print(data.iloc[2, [3, 0, 1]], '\n') # 以NumPy的语言风格选择——先选轴0,再选轴1(就是将二维数组降维分别选择)
""" 过滤 """
print(data.iloc[:, :3][data.three > 5])
4.运算、数据对齐
将两个对象相加时,如果存在某个索引对不相同,则返回结果的索引将是索引对的并集,这类似于索引标签的自动连接(outer join)。
import pandas as pd
s1 = pd.Series([7.3, -2.5, 3.4, 1.5], index=['a', 'c', 'd', 'e'])
s2 = pd.Series([-2.1, 3.6, -1.5, 4, 3.1], index=['a', 'c', 'e', 'f', 'g'])
""" print("s1:\n", s1, '\n')
print("s2:\n", s2, '\n')
print("s1+s2:\n", s1+s2, '\n') """
data1 = pd.DataFrame(np.arange(9.).reshape((3, 3)), columns=list('bcd'), index=['Ohio', 'Texas', 'Colorado'])
data2 = pd.DataFrame(np.arange(12.).reshape((4, 3)), columns=list('bde'), index=['Utah', 'Ohio', 'Texas', 'Oregon'])
print("data1:\n", data1, '\n')
print("data2:\n", data2, '\n')
print("data1+data2:\n", data1+data2, '\n')
①使用填充值的算术方法
比如当轴标签在一个对象中存在,在另一个对象中不存在时,打算将缺失值填充为0
算术方法:
方法 | 描述 |
---|---|
add, radd | 加法 + |
sub, rsub | 减法 - |
div, rdiv | 除法 / |
floordiv, rfloordiv | 整除 // |
mul, rmul | 乘法 * |
pow, rpow | 幂次方 ** |
import pandas as pd
df1 = pd.DataFrame(np.arange(12.).reshape((3, 4)), columns=list('abcd'))
df2 = pd.DataFrame(np.arange(20.).reshape((4, 5)), columns=list('abcde'))
# 将 df2 上某位置的值改为NaN
df2.loc[1, 'b'] = np.nan
# 在 df1 上使用add方法,将 df2 和一个fill_value作为参数传入
print(df1.add(df2, fill_value=0))
# 也可以用fill_value传参重建df1的索引
df1.reindex(columns=df2.columns, fill_value=0)
②DataFrame和Series间的操作
广播机制(broadcasting)
import pandas as pd
# 行匹配
arr = np.arange(12.).reshape((3, 4))
print('arr:\n', arr, '\n')
print('arr - arr[0]:\n', arr - arr[0], '\n')
# 列匹配
frame = pd.DataFrame(np.arange(12.).reshape((4, 3)),
columns=list('bde'),
index=['Utah', 'Ohio', 'Texas', 'Oregon'])
series = frame.iloc[0]
print('series: \n', series, '\n')
print('frame - series: \n', frame-series, '\n')
# 重建索引——:两数据结构不同时具有某索引标签
series2 = pd.Series(range(3), index=['b', 'e'`,` 'f']) # frame不具有'e'和'f'索引标签
# 在列上匹配:
series2 = frame['d']
# 在行上广播:
print('frame.sub(series2, axis=\'index\') -> \n', frame.sub(series2, axis='index'))
5.函数应用和映射
import pandas as pd
# NumPy的通用函数(逐元素数组法)对pandas对象也有效
frame = pd.DataFrame(np.random.randn(4, 3),
columns=list('bde'),
index=['Utah', 'Ohio', 'Texas', 'Oregon'])
np.abs(frame) # 将frame中的所有元素都取其绝对值
# 将函数应用到一行或一列的一维数组上
f = lambda x: x.max() - x.min()
frame.apply(f) # 计算frame的每一列中最大值减去最小值的差值
frame.apply(f, axis='columns') # 在每列调用后的基础上,在每行都调用一遍
# 根据frame中的每个浮点数计算一个格式化字符串
formatting = lambda x:'%.2f' % x
frame.applymap(formatting)
6.排序和排名
-
sort_index()
返回一个新的、排序好的对象 -
rank()
通过将平均排名分配到每个组来打破平级的关系,参数如下:
方法 | 描述 |
---|---|
average | 默认:在小组中的平均排名 |
min | 对整个组使用最小排名 |
max | 对整个组使用最大排名 |
first | 按照值在数据中出现的次序分配排名 |
dense | 类似于"method=min",但组间排名总是增加1,而不是一个组中的相等元素的数量 |
import pandas as pd
obj = pd.Series(range(4), index=['d', 'a', 'b', 'c'])
frame = pd.DataFrame(np.random.randn(4, 3),
columns=list('bde'),
index=['Utah', 'Ohio', 'Texas', 'Oregon'])
""" 按轴标签排序 """
print('按轴标签排序-> obj默认按升序排序:\n', obj.sort_index())
# 在各个轴上排序,数据默认升序排序
print('\n按轴标签排序-> frame在轴1按降序排序:\n', frame.sort_index(axis=1, ascending=False))
""" 按值排序 """
print('\n按值排序-> 默认情况下NaN被排序至尾部:\n', obj.sort_values())
# 可以选择多列或一列作为排序键
frame = pd.DataFrame({'b': [4, 7, -3, 2], 'a': [0, 1, 0, 1]}) # 按数值大小分配排名
print('\n按值排序-> 选择某一列作为排序键:\n', frame.sort_values(by='b'))
""" rank()方法输出排序后的名次 """
obj = pd.Series([7, -5, 7, 4, 2, 0, 4])
print("\n索引:名次\n", obj.rank())
# 将值分配给组中最大排名
obj.rank(ascending=False, method='max')
# DataFrame列排名
frame.rank(axis='columns')
7.含有重复标签的轴索引
is_unique()
属性可以告诉你一个Series的标签是否唯一
import pandas as pd
obj = pd.Series(range(5), index=['a', 'a', 'b', 'b', 'c'])
print('obj的索引唯一:', obj.index.is_unique)
print(obj['a'], '\n') # 无重复索引的返回一个标量值,有重复索引值的返回一个序列
df = pd.DataFrame(np.random.randn(4, 3), index=['a', 'a', 'b', 'c'])
print(df.loc['b'])
三、描述性统计的概述与计算
1.归约方法
可选参数如下:
方法 | 描述 |
---|---|
axis | 归约轴,0为行向,1为列向 |
skipna | 排除缺失值,默认为True |
level | 如果轴是多层索引的(MultiIndex),该参数可以缩减分组层级 |
import pandas as pd
""" 归约型方法 """
df = pd.DataFrame([[1.4, np.nan], [7.1, -4.5],
[np.nan, np.nan], [0.75, -1.3]],
index=['a', 'b', 'c', 'd'],
columns=['one', 'two'])
# 特此提醒:除非整列上都是NaN值,否则输出时NaN值是被自动排除的
print(df.sum(axis=1), '\n') # 或 axis='columns',将一行上各个列的值相加
# 可以通过禁用 skipna 来实现不排除NaN值
print(df.mean(axis='columns', skipna=False))
2.汇总统计
方法 | 描述 |
---|---|
count | 非Na值的个数 |
describe | 计算Series或DataFrame各列的汇总统计集合 |
min, max | 计算最小值、最大值 |
argmin, argmax | 分别计算最小值、最大值所在的索引位置(整数) |
idmin, idmax | 分别计算最小值或最大值的索引标签 |
quantile | 计算样本的从0到1间的分位数 |
sum | 加和 |
mean | 均值 |
median | 中位数(50%分位数) |
mad | 平均值的平均绝对偏差 |
prod | 所有值的积 |
var | 值的样本方差 |
std | 值的样本标准差 |
skew | 样本偏度(第三时刻)值 |
kurt | 样本峰度(第四时刻)值 |
cumsum | 累计值 |
cummin, cummax | 累计值得最小值或最大值 |
cumprod | 值的累计值 |
diff | 计算第一个算术差值(对时间序列有用) |
pct_change | 计算百分比 |
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=['a', 'b', 'c', 'd'],
columns=['one', 'two'])
print(df.cumsum())
输出为:
one two
a 1.40 NaN
b 8.50 -4.5
c NaN NaN
d 9.25 -5.8
3.唯一值、计数和成员属性
方法 | 描述 |
---|---|
isin | 计算表征Series中每个值是否包含于传入序列的布尔值数组中 |
match | 计算数组中每个值的整数索引,形成一个唯一值数组。有助于数据对齐和join类型的操作 |
unique | 计算Series值中的唯一值数组,按照观察顺序返回 |
value_counts | 返回一个Series,索引值是唯一值序列,值是计数个数,按照个数降序排序 |
import pandas as pd
obj = pd.Series(['c', 'a', 'd', 'a', 'a', 'b', 'b', 'c', 'c' ])
uniques = obj.unique() # 返回唯一值索引标签
print("唯一值索引标签:", uniques, '\n')
print("唯一值索引标签个数:\n", obj.value_counts(), '\n')
# 过滤为值子集
mask = obj.isin(['b', 'c'])
print(mask, '\n')
print("过滤后的值子集为:\n", obj[mask], '\n')
# 将非唯一值数组转换成另一个唯一值数组
print("将非唯一值数组转换成另一个唯一值数组:\n", pd.Index(uniques).get_indexer(obj))
更多推荐
所有评论(0)