1. pandas的数据结构
Series:类似于数组
DataFrame:类似于表格
Panel:Excel多表单Sheet【不常用】
series:一维数组对象,通过索引来访问
1.创建:可通过列表和字典来创建
import pandas as pd
import numpy as np
s1 = pd.Series([1,4,'ab',0])
s2 = pd.Series({'A':'111', 'B':'你好', 'C':'345'})
print(s1,'\t',s2)
#>>>>>>>输出结果:
0 1
1 4
2 ab
3 0
dtype: object A 111
B 你好
C 345
dtype: object
2.索引
(1)列表建立Series对象时,没有指定index,会自己生成整数型索引,可用使用索引切片技术;指定index时,Series会有两种描述某数据的手段,自己生成的整数位置索引和建立Series对象时给定的index索引(标签);dtype用来给定数据类型。
import pandas as pd
list1 = [1,3,5,7]
s1 = pd.Series(list1, index=['a1', 'b1', 'c1', 'd1'], dtype='object')
print('s1 index索引取值',s1['a1'])
print('s1 位置取值',s1[0])
#>>>>>>>结果:
s1 index索引取值 1
s1 位置取值 1
(2)字典建立Series对象时,不指定index,默认会用字典键有序排列来做索引;指定index时,如果键值与指定的index不匹配,会生成NaN(非数字);给定的index索引可用通过赋值方式修改
import pandas as pd
dic = {
'a':'中国',
'b':'日本',
'd':'美国'
}
s = pd.Series(dic, index=['a', 'b', 'c', 'd'])
print(s)
s.index = ['A', 'B', 'C','D']
#>>>>>>>结果:
a 中国
b 日本
c NaN
d 美国
dtype: object
修改index: A 中国
B 日本
C NaN
D 美国
dtype: object
DataFrame:有一组有序的列,表格型的数据结构
1.创建:最常用的是直接传入一个由等长列表或者NumPy数组组成的字典来形成DataFrame。
2.特性:会自动加上索引,且全部列会被有序排列,如果columns指定列名序列,则按指定列名排列;index给出行标签;如果传入的列在数据中找不到,会产生NaN值。
data = {
'name':['张飞', '孙尚香', '韩信', '貂蝉', '马超'],
'location':['游走', '下路', '打野', '中单', '上单'],
'dynasty':['蜀', '蜀', '战国', '汉', '蜀'],
'year':[1999, 2000, 2020, 2050, 3030]
}
df = pd.DataFrame(data)
print(df)
#>>>>>>结果:
name location dynasty year
0 张飞 游走 蜀 1999
1 孙尚香 下路 蜀 2000
2 韩信 打野 战国 2020
3 貂蝉 中单 汉 2050
4 马超 上单 蜀 3030
df = pd.DataFrame(data, columns=['name','location','dynasty','address','year'],index=['a','b','c','d','e'])
print(df)
#>>>>>>>>结果:
name location dynasty address year
a 张飞 游走 蜀 NaN 1999
b 孙尚香 下路 蜀 NaN 2000
c 韩信 打野 战国 NaN 2020
d 貂蝉 中单 汉 NaN 2050
e 马超 上单 蜀 NaN 3030
索引对象
1.pandas的索引对象负责管理轴标签和其它元数据信息(例如轴名称等),构建Series和DataFrame时,所用到的任何数组或其它序列的标签,都会被转换成一个Index。
print(df.index)
print(df.columns)
#>>>>>>>结果:
Index(['a', 'b', 'c', 'd', 'e'], dtype='object')
Index(['name', 'location', 'dynasty', 'address', 'year'], dtype='object')
2.Index长的像数组,功能类似于一个固定大小的集合。不可修改保证Index在多个数据结构间的安全共享。
print('name' in df.columns)
df.index=['1','2','3','4','5']
df.columns=['a','b','c','d','e']
print(df)
#>>>>>>>结果:
True
a b c d e
1 张飞 游走 蜀 NaN 1999
2 孙尚香 下路 蜀 NaN 2000
3 韩信 打野 战国 NaN 2020
4 貂蝉 中单 汉 NaN 2050
5 马超 上单 蜀 NaN 3030
3.索引的方法和属性
方法 | 属性 |
---|---|
append | 连接另一个Index对象,产生一个新的Index对象 |
diff | 计算差集并得到一个Index |
intersection | 计算交集 |
union | 计算并集 |
isin | 计算一个指示各值是否都包含在参数集合中的布尔型数组 |
delete | 删除索引i处的元素,并得到新的Index |
drop | 删除传入的值,并得到新的Index |
insert | 将元素插入索引i处,并得到新的索引 |
is_monotonic | 当各元素均大于或等于前一个元素时,返回True |
is.unique | 当Index没有重复值时,返回True |
unique | 计算Index中唯一值的数组 |
df.index.insert(1,'w')
#>>>>>>>结果:
Index(['1', 'w', '2', '3', '4', '5'], dtype='object')
查看DataFrame的常用属性
属性 | 描述 |
---|---|
values | 元素,返回二维嵌套列表 |
index | 索引,返回Index |
columns | 列名 |
dtypes | 类型 |
ndim | 维度 |
shape | 形状 |
size | 元素的个数 |
print(df)
print("--------------")
print(df.values())
print("--------------")
print(df.index())
print("--------------")
print(df.columns())
print("--------------")
print(df.dtypes())
print("--------------")
print(df.ndim())
print("--------------")
print(df.shape())
print("--------------")
print(df.size())
#>>>>>>>结果:
a b c d e
1 张飞 游走 蜀 NaN 1999
2 孙尚香 下路 蜀 NaN 2000
3 韩信 打野 战国 NaN 2020
4 貂蝉 中单 汉 NaN 2050
5 马超 上单 蜀 NaN 3030
--------------
[['张飞' '游走' '蜀' nan 1999]
['孙尚香' '下路' '蜀' nan 2000]
['韩信' '打野' '战国' nan 2020]
['貂蝉' '中单' '汉' nan 2050]
['马超' '上单' '蜀' nan 3030]]
--------------
Index(['1', '2', '3', '4', '5'], dtype='object')
--------------
Index(['a', 'b', 'c', 'd', 'e'], dtype='object')
--------------
a object
b object
c object
d object
e int64
dtype: object
--------------
2
--------------
(5, 5)
--------------
25
2.Pandas的索引操作
索引对象是无法修改的,因此重建索引是指对索引的重新排序而不是重新命名,如果某个索引值不存在的话会引入缺失值。
重建索引
1.重建索引
import pandas as pd
import numpy as np
obj = pd.Series([3,4.5,9,0], index = ['a','c','b','d'])
print(obj)
obj.reindex(['a','b','c','d','e'])
》》》》》》结果:
a 3.0
c 4.5
b 9.0
d 0.0
dtype: float64
a 3.0
b 9.0
c 4.5
d 0.0
e NaN
dtype: float64
###### 2.填充重建索引时引入的缺失值【前向与后向填充】
```python
#填充缺失值
obj.reindex(['a','c','c','d','e'], fill_value=10)
》》》》》》结果:
a 3.0
c 4.5
c 4.5
d 0.0
e 10.0
dtype: float64
#前向填充和后向填充:method='ffill\bfill'
obj1 = pd.Series(['blue','red','black'], index = [0,2,4])
obj1.reindex(np.arange(6), method = 'ffill')
>>>>>结果:
0 blue
1 blue
2 red
3 red
4 black
5 black
dtype: object
obj2 = pd.Series(['blue','red','black'], index = [0,2,4])
obj2.reindex(np.arange(6), method = 'bfill')
>>>>>结果:
0 blue
1 red
2 red
3 black
4 black
5 NaN
dtype: object
3.reindex操作
参数 | 说明 |
---|---|
index | 用于索引的新序列 |
method | 插值(填充)方式【ffill[pad]、bfill[backfill]】 |
fill_value | 缺失值替换值 |
limit | 最大填充数 |
leve copy | 在Multiindex的指定级别上匹配简单索引,否则取决其子集默认为True,无论如何都复制;如果为False,则新旧相等时不复制 |
对于DataFrame,reindex可以修改(行)索引、列,或两个都修改。如果只传入一个序列,则结果中的行会重建索引。
更换索引
在DataFrame数据中,如果不想用默认的行索引,则可以在创建时通过Index参数来设置。有时希望将列数据作为索引,可以用set_index方法来实现。与set_index相反的是reset_index。
data = {
'name':['张飞', '孙尚香', '韩信', '貂蝉', '马超'],
'location':['游走', '下路', '打野', '中单', '上单'],
'dynasty':['蜀', '蜀', '战国', '汉', '蜀'],
'year':[1999, 2000, 2020, 2050, 3030]
}
df = pd.DataFrame(data, columns=['name','location','dynasty','address','year'],index=['a','b','c','d','e'])
df1 = df.set_index('dynasty')
print(df1)
name location address year
dynasty
蜀 张飞 游走 NaN 1999
蜀 孙尚香 下路 NaN 2000
战国 韩信 打野 NaN 2020
汉 貂蝉 中单 NaN 2050
蜀 马超 上单 NaN 3030
3.DataFrame数据的查询和编辑
查询【一般都是通过索引来操作的】
1.选取列
通过列索引标签或者属性的方式可以单独获取DataFrame的列数据,返回数据类型为Series。在选取列时不能使用切片的方式,超过一个列名用df[['列名1','列名2']]
#选取列
import pandas as pd
import numpy as np
data = {
'name':['张三','李四','王麻子'],
'age':[21,19,23],
'address':['兰州','上海','北京']
}
df = pd.DataFrame(data)
print(df)
w1 = df['name']
print("以列名取一列数据:\n", w1)
w2 = df[['name','age']]
print("以列名取两份数据:\n", w2)
name age address
0 张三 21 兰州
1 李四 19 上海
2 王麻子 23 北京
以列名取一列数据:
0 张三
1 李四
2 王麻子
Name: name, dtype: object
以列名取两份数据:
name age
0 张三 21
1 李四 19
2 王麻子 23
2.选取行
通过行索引或者行索引位置切片形式获取行数据【从0开始的,左闭右开】。DataFrame提供的head【开头开始】和tail【结尾】可以取连续多行数据,sample可以随机抽取并显示数据
#取行 从0开始的
print('显示前两行:\n', df[:2])
print('显示2行:\n', df[1:2])
#head从第一行取,默认前五行
print(df.head())
print(df.head(1))
#tail默认最后五行 可以带数字取最后的
print(df.tail())
print(df.tail(1))
#sample随机抽取n行显示
print(df.sample(2))
显示前两行:
name age address
0 张三 21 兰州
1 李四 19 上海
显示2行:
name age address
1 李四 19 上海
name age address
0 张三 21 兰州
1 李四 19 上海
2 王麻子 23 北京
name age address
0 张三 21 兰州
name age address
0 张三 21 兰州
1 李四 19 上海
2 王麻子 23 北京
name age address
2 王麻子 23 北京
name age address
2 王麻子 23 北京
1 李四 19 上海
3.读取行和列
切片选取行限制比较大,取单独的几行数据可以采用Pandas提供的iloc和loc方法实现。
用法:DataFrame.loc(行索引位置, 列索引位置)
DataFrame.loc(行索引名称或条件, 列索引名称)
#loc
data = {
'name':['张飞', '孙尚香', '韩信', '貂蝉', '马超'],
'location':['游走', '下路', '打野', '中单', '上单'],
'dynasty':['蜀', '蜀', '战国', '汉', '蜀'],
'year':[1999, 2000, 2020, 2050, 3030]
}
df1 = pd.DataFrame(data, columns=['name','location','dynasty','address','year'],index=['a','b','c','d','e'])
df2 = df1.set_index('dynasty')
print(df2)
print("取name和year两列的数据:\n",df2.loc[:,['name','year']])
print("取汉,战国行中name,year的数据:\n",df2.loc[['汉','战国'],['name','year']])
name location address year
dynasty
蜀 张飞 游走 NaN 1999
蜀 孙尚香 下路 NaN 2000
战国 韩信 打野 NaN 2020
汉 貂蝉 中单 NaN 2050
蜀 马超 上单 NaN 3030
取name和year两列的数据:
name year
dynasty
蜀 张飞 1999
蜀 孙尚香 2000
战国 韩信 2020
汉 貂蝉 2050
蜀 马超 3030
取汉,战国行中name,year的数据:
name year
dynasty
汉 貂蝉 2050
战国 韩信 2020
#iloc [索引0开始]
print("显示前两列:\n", df2.iloc[:, 2])
print("显示第1和第3行的第2列:\n", df2.iloc[[1,3],[0]])
显示前两列:
dynasty
蜀 1999
蜀 2000
战国 2020
汉 2050
蜀 3030
Name: year, dtype: int64
显示第1和第3行的第二列:
name
dynasty
蜀 孙尚香
汉 貂蝉
也可以使用ix方法实现行和列的选择,同时支持索引标签和索引位置取值。
4.布尔选择
用选择符不等于(!=)、与(&)、或(|)
df3 = df2[df2['year'] == 3030]
print(df3,type(df3))#返回dataframe型
df2['name']=='孙尚香'#返回布尔类型
name location year
dynasty
蜀 马超 上单 3030 <class 'pandas.core.frame.DataFrame'>
dynasty
蜀 False
蜀 True
战国 False
汉 False
蜀 False
Name: name, dtype: bool
编辑【提取需要编辑的数据,重新赋值】
1.增加数据
增加一行通过append方法传入字典结构数据即可,增加列时为增加的列赋值即可创建一个新的列,具体给值要对应,不然会报错
#插入一行数据append
#加列并赋值
df1['C'] = 10
df1['age'] = [24,33,19,40,80]
data1 = {
'name':'李白',
'location':'打野',
'dynasty':'唐',
'year':'1909'
}
df1.append(data1,ignore_index=True)
name location dynasty year C age
0 张飞 游走 蜀 1999 10 24
1 孙尚香 下路 蜀 2000 10 33
2 韩信 打野 战国 2020 10 19
3 貂蝉 中单 汉 2050 10 40
4 马超 上单 蜀 3030 10 80
name location dynasty year C age
0 张飞 游走 蜀 1999 10.0 24.0
1 孙尚香 下路 蜀 2000 10.0 33.0
2 韩信 打野 战国 2020 10.0 19.0
3 貂蝉 中单 汉 2050 10.0 40.0
4 马超 上单 蜀 3030 10.0 80.0
5 李白 打野 唐 1909 NaN
2.删除数据
删除数据直接用drop方法,行列数据通过axis参数设置默认为0删除行,1删除列。默认数据删除不修改原数据,如果在原数据上删除加入参数inplace=True即可。
#删除数据的行和列 没有指定inplace=True,删除不是在原数据上操作的
df1.drop('C',axis=1)
print(df1)
name location dynasty year C age
0 张飞 游走 蜀 1999 10 24
1 孙尚香 下路 蜀 2000 10 33
2 韩信 打野 战国 2020 10 19
3 貂蝉 中单 汉 2050 10 40
4 马超 上单 蜀 3030 10 80
df1.drop('C',axis=1,inplace=True)
print(df1)
name location dynasty year age
0 张飞 游走 蜀 1999 24
1 孙尚香 下路 蜀 2000 33
2 韩信 打野 战国 2020 19
3 貂蝉 中单 汉 2050 40
4 马超 上单 蜀 3030 80
3.修改数据
对选择的数据进行赋值就可以了。**修改数据是对DataFrame值的修改,无法撤销。**如新列赋值。
4.pandas数据运算
算术运算
如果有相同索引则进行算术运算,如果没有则会进行数据对齐,但会引入缺失值。对于DataFrame类型,数据对齐的操作会同时发生在行和列上。
import pandas as pd
import numpy as np
##Series相加
obj1 = pd.Series([1,4,-1,9,0,-8], index=['a','b','d','e','f','g'])
obj2 = pd.Series([4,9,0,-4,-1,10], index=['a','c','d','e','f','h'])
print("obj1:\n",obj1)
print("obj2:\n",obj2)
print(obj1+obj2)
obj1:
a 1
b 4
d -1
e 9
f 0
g -8
dtype: int64
obj2:
a 4
c 9
d 0
e -4
f -1
h 10
dtype: int64
a 5.0
b NaN
c NaN
d -1.0
e 5.0
f -1.0
g NaN
h NaN
dtype: float64
## DataFrame 行和列均会对齐给NaN值
import pandas as pd
import numpy as np
df1 = pd.DataFrame(np.arange(12).reshape(3,4), columns=['a','b','c','d'], index=['A','B','C'])
df2 = pd.DataFrame(np.arange(9).reshape(3,3), columns=['a','c','d'], index=['A','B','D'])
print("df1:\n",df1)
print("df1:\n",df2)
print(df1+df2)
df1:
a b c d
A 0 1 2 3
B 4 5 6 7
C 8 9 10 11
df1:
a c d
A 0 1 2
B 3 4 5
D 6 7 8
a b c d
A 0.0 NaN 3.0 5.0
B 7.0 NaN 10.0 12.0
C NaN NaN NaN NaN
D NaN NaN NaN NaN
函数的应用和映射
1.定义函数进行较为复杂的数据处理过程
(1).map
函数:将函数套入到Series的每个元素中
(2).apply
函数:将函数套用到DataFrame的行和列上,行和列通过axis参数指定。
(3).applymap
函数:将函数套用到DataFrame的每个元素上。
匿名函数:lambda 参数列表 : 关于参数的表达式
e.g:lambda x,y:x+y:该函数的输入是x和y,输出是x+y的值
#去掉水果价格中的 元 字
data = {'fruit':['apple','grape','banana'],'price':['30元','40元','50元']}
df = pd.DataFrame(data)
print(df)
def f1(x):
return x.split('元')[0]#按’元‘分割 取第一个位置的
df['price'] = df['price'].map(f1)#map函数会循环给所给数据的每一个元素执行f1函数
print(df)
fruit price
0 apple 30元
1 grape 40元
2 banana 50元
fruit price
0 apple 30
1 grape 40
2 banana 50
##apply函数 套用到df的行与列 axis[轴] axis=1 按行运算
df = pd.DataFrame(np.random.randn(3,3), columns=['a','b','c'], index=['app','win','mic'])
print(df)
df.apply(np.mean,axis=1)
a b c
app -0.336255 -0.446342 -0.888068
win 2.742748 2.432790 -1.444682
mic 0.567298 -0.268666 0.039183
app -0.556888
win 1.243619
mic 0.112605
dtype: float64
##applymap 套用到df每个元素 对整个df进行批量处理
#匿名函数:lambda 参数列表 : 关于参数列表的表达式(一行)【输入是传递进来的参数列表的值,输出是根据表达式计算所得的值】
print(df)
df.applymap(lambda x:'%.3f'%x)
a b c
app -0.336255 -0.446342 -0.888068
win 2.742748 2.432790 -1.444682
mic 0.567298 -0.268666 0.039183
a b c
app -0.336 -0.446 -0.888
win 2.743 2.433 -1.445
mic 0.567 -0.269 0.039
排序
在Series中,通过sort_index
方法对索引进行排序,通过sort_values
对数值进行排序,默认升序,降序加参数ascending=False
。
##排序 Series dataframe sort_index([ascending=False]) 默认升序,False降序 sort_values([by='列名'])
obj = pd.Series([-1,0,-9,9,5],index=['a','c','b','e','d'])
print('值排序:\n',obj.sort_values())
print('索引降序:\n',obj.sort_index(ascending=False))
值排序:
b -9
a -1
c 0
d 5
e 9
dtype: int64
索引降序:
e 9
d 5
c 0
b -9
a -1
dtype: int64
对于DataFrame的排序,通过指定axis轴的方向,使用sort_index
对行或列索引进行排序,若要进行列排序,用sort_values(by='列名')
。
#DataFrame
print(df)
print(df.sort_values(by='a'))
a b c
app -0.336255 -0.446342 -0.888068
win 2.742748 2.432790 -1.444682
mic 0.567298 -0.268666 0.039183
a b c
app -0.336255 -0.446342 -0.888068
mic 0.567298 -0.268666 0.039183
win 2.742748 2.432790 -1.444682
统计汇总
1.数据汇总:sum
函数可以对每列求和汇总。axis=1
可以实现按行汇总
##数据汇总 axis=1是按行 默认按列
print(df)
print('按列汇总:\n',df.sum())
print('按行汇总:\n',df.sum(axis=1))
a b c
app -0.336255 -0.446342 -0.888068
win 2.742748 2.432790 -1.444682
mic 0.567298 -0.268666 0.039183
按列汇总:
a 2.973791
b 1.717783
c -2.293567
dtype: float64
按行汇总:
app -1.670665
win 3.730856
mic 0.337815
dtype: float64
2.数据的描述与统计
描述性统计表:
方法名称 | 说明 | 方法名称 | 说明 |
---|---|---|---|
min | 最小值 | max | 最大值 |
mean | 均值 | ptp | 极差 |
std | 标准差 | var | 方差 |
cov | 协方差 | sem | 标准误差 |
median | 中位数 | mode | 众数 |
skew | 样本偏度 | kurt | 样本峰度 |
quantitle | 四分位数 | count | 非空值数目 |
describe | 统计描述 | mad | 平均绝对离差 |
对于类别型特征的描述性统计,可以使用频数统计表。unique获取不重复的值。value_counts实现频数统计。
#数据的描述与统计
obj = pd.Series([1,2,3,0,5,6,0,0,3])
print('去重:\n',obj.unique())
print('频数统计:\n',obj.value_counts())
去重:
[1 2 3 0 5 6]
频数统计:
0 3
3 2
1 1
2 1
5 1
6 1
dtype: int64
5.数据分组与聚合
数据分组
1.groupby方法:DataFrame.groupby(by=None, axis=0, level=None, as_index=True, sort=True, group_keys=True, squeeze=False)
参数名称 | 参数说明 |
---|---|
by | 可以传入函数、字典、Series等,用于分组的依据条件 |
axis | 0或者1,表示操作的轴方向默认按列操作,取1按行操作 |
level | 接收int或者索引名,代表标签所在的级别,默认None |
as_index | 接收boolean,表示聚合后的聚合标签是否以DataFrame的索引输出,默认True |
sort | 接收boolean,对分组依据和分组标签排序,默认True |
group_keys | 接收boolean,表示是否显示分组标签的名称,默认True |
squeeze | 接收Boolean,表示是否在允许情况下对数据进行降维操作,默认False |
参数by,如果传入函数,则对索引进行计算并分组;如果传入字典或者Series,则字典或者Series的值作为分组依据;如果传入Numpy数组,则数据元素作为分组依据;如果传入字符串或者字符串列表,则用这些字符串所代表的字段作为分组依据。
数据分组之后返回的是一个groupby对象,可以调用该对象的方法如size返回一个含有分组大小的Series。
#取df['data1']这一列数据并按df['key1']这一列的数据来分组 分完之后a:3 ,b:2
import numpy as np
import pandas as pd
##groupby()
df = pd.DataFrame({
'key1':['a','a','b','b','a'],
'key2':[1,0,1,1,0],
'data1':np.random.randn(5),
'data2':np.random.randn(5)
})
print(df)
grouped = df['data1'].groupby(df['key1'])
print(grouped.size())
print(grouped.mean())
key1 key2 data1 data2
0 a 1 0.410518 0.204681
1 a 0 -0.558132 -0.008501
2 b 1 -0.008334 -1.935630
3 b 1 -0.481743 0.775196
4 a 0 0.597605 0.561882
key1
a 3
b 2
Name: data1, dtype: int64
key1
a 0.149997
b -0.245038
Name: data1, dtype: float64
2.按列名分组:DataFrame数据的列索引名可以作为分组键,但是用于分组的对象必须是DataFrame本身。不然会报错找不到索引名称。
#按列索引名称分组
grouped1 = df.groupby('key1').size()
grouped2 = df.groupby('key1').mean()
print(grouped1)
grouped2
key1
a 3
b 2
dtype: int64
key2 data1 data2
key1
a 0.333333 0.149997 0.252688
b 1.000000 -0.245038 -0.580217
3.按列表或元组分组:分组键还可以是和DataFrame行数相等的列表或者元组,相当于把列表或者元组当成DataFrame的一列,然后分组。
##所给的按列表或元组
w = ['w','w','y','w','y']
df.groupby(w).sum()
key2 data1 data2
w 2 -0.629356 0.971377
y 1 0.589272 -1.373748
4.按字典分组:如果原始的DataFrame中分组信息难以确定或不存在,则可以通过字典结构定义一个分组信息。
#定义一个字典来分组 分组信息:不区分大小写来分组
df = pd.DataFrame(np.random.normal(size=(6,5)), index=['a','b','A','B','c','C'])
print(df)
dic = {
"a":'one',
"b":'two',
"c":'three',
"A":'one',
"B":'two',
"C":'three'
}
x = df.groupby(dic)
print(x.sum())
0 1 2 3 4
a -0.422562 1.962075 -0.489384 -1.304302 -1.109478
b 1.134703 -0.358548 -1.373025 0.851012 -0.302279
A -0.196233 -0.192463 0.286070 0.872550 -0.835654
B -0.038677 -0.130829 -0.599642 -0.201865 -1.849057
c -0.033203 -0.512046 -0.414564 0.516591 1.191699
C -1.145768 0.176744 -0.160164 1.435075 -0.124890
0 1 2 3 4
one -0.618795 1.769613 -0.203314 -0.431753 -1.945131
three -1.178971 -0.335301 -0.574728 1.951666 1.066808
two 1.096026 -0.489377 -1.972667 0.649148 -2.151336
5.按函数分组:类似于字典,通过映射关系来进行分组
#函数
def judge(x):
if x>=0:
return 'a'
else:
return 'b'
df = pd.DataFrame(np.random.randn(4,4))
print(df)
print(df[3].groupby(df[3].map(judge)).sum())
0 1 2 3
0 0.714710 -1.180971 0.177371 1.257526
1 -0.465390 0.822470 1.767948 0.740839
2 0.194928 0.658354 -0.053870 -0.657892
3 1.001120 -1.195080 1.122340 -1.813876
a 1.998365
b -2.471768
Name: 3, dtype: float64
数据聚合:对分组后的数据进行计算,产生标量值的数据转换过程。
1.聚合函数:在聚合运算中,空值不参加计算。
函数 | 使用说明 |
---|---|
count | 计数 |
sum | 求和 |
mean | 平均值 |
median | 中位数 |
std、var | 无偏标准差和方差 |
min、max | 最小、最大值 |
prod | 求积 |
first、last | 第一个和最后一个值 |
2.agg方法实现聚合数据:支持对每个分组应用某个函数。能直接对DataFrame进行函数应用操作。
#agg
## 使用agg求出当前数据对应的统计量
data = pd.read_excel('D:\python\数据分析与可视化\第四章:pandas统计分析基础\data\\testdata.xls')
print(data.head())
print('求当前数据的各项统计量:\n',data[['淋巴细胞计数','白细胞计数']].agg([np.sum, np.mean]))
## 使用agg函数分别求各字段不同的统计量
print('求个字段的不同统计量:\n',data.agg({'淋巴细胞计数':np.mean, '白细胞计数':np.std}))
## 计算不同字段不同数目的统计量
print('计算不同字段不同数目的统计量:\n',data.agg({'淋巴细胞计数':np.mean, '白细胞计数':[np.std, np.mean]}))
## 统计不同性别人群的血小板计数的平均值
print('统计不同性别人群的血小板计数:\n',data.groupby('性别')['血小板计数'].agg(np.mean))
## 返回的数据不希望以分组键为索引 as_index=False实现
print('统计不同性别人群的血小板计数:\n',data.groupby('性别',as_index=False)['血小板计数'].agg(np.mean))
序号 性别 身份证号 是否吸烟 是否饮酒 开始从事某工作年份 体检年份 淋巴细胞计数 白细胞计数 细胞其它值 \
0 1 女 ****1982080000 否 否 2009年 2017 2.4 8.5 NaN
1 2 女 ****1984110000 否 否 2015年 2017 1.8 5.8 NaN
2 3 男 ****1983060000 否 否 2013年 2017 2.0 5.6 NaN
3 4 男 ****1985040000 否 否 2014年 2017 2.5 6.6 NaN
4 5 男 ****1986040000 否 否 2014年 2017 1.3 5.2 NaN
血小板计数
0 248.0
1 300.0
2 195.0
3 252.0
4 169.0
求当前数据的各项统计量:
淋巴细胞计数 白细胞计数
sum 4280.270000 6868.008100
mean 3.849164 6.176266
求个字段的不同统计量:
淋巴细胞计数 3.849164
白细胞计数 12.043418
dtype: float64
计算不同字段不同数目的统计量:
淋巴细胞计数 白细胞计数
mean 3.849164 6.176266
std NaN 12.043418
统计不同性别人群的血小板计数:
性别
女 212.687636
男 194.727417
Name: 血小板计数, dtype: float64
统计不同性别人群的血小板计数:
性别 血小板计数
0 女 212.687636
1 男 194.727417
分组运算:包含聚合运算,聚合运算是数据转换的特例。
1.transform方法:将运算分不到每一行
# 分组运算
## transform 运算分布到每一行
data.groupby('性别')['血小板计数'].transform('mean').sample(5)
915 194.727417
1039 194.727417
1062 194.727417
95 194.727417
416 212.687636
Name: 血小板计数, dtype: float64
2.apply方法:类似于agg方法,可以将函数应用于每一列
## apply 函数应用到每列 axis=1 应用到每行
data.groupby(['性别','是否吸烟'])['血小板计数'].apply(np.mean)
性别 是否吸烟
女 否 212.133188
是 297.333333
男 否 194.236749
是 195.210175
重要技巧: groupby
之后直接.reset_index()
可以得到一个没有多级索引的DataFram,之后可以通过df.rename({‘old_col1’:‘new_col1’,‘old_col2’:‘new_col2’,…})
重命名
df1= df.groupby([‘date’])[‘price’].agg({‘sum’,‘count’}).reset_index()
6.数据透视表
数据透视表(Pivot Table)是数据分析中常见的工具之一,根据一个或多个键值对对数据进行聚合,根据列或行的分组键将数据划分到各个区域。
透视表
groupby()、pivot_table():均可以实现透视功能。
pivot_table(data, values=None, index=Nane, columns=None, aggfunc='mean', fill_value=None, margins=False, dropna=True, margins_name='All')
参数 | 使用说明 |
---|---|
data | 接收DataFrame,创建表的数据 |
values | 接收string,指定聚合的数据字段,默认全部 |
index | 接收string或list,行分组键 |
columns | 接收string或list,列分组键 |
aggfunc | 接收函数,表示聚合函数,默认mean |
margins | 接收boolean,表示汇总功能开关 |
dropna | 接收boolean,表示是否删除掉全为NaN的列,默认False |
import numpy as np
import pandas as pd
data = pd.DataFrame({
'k1':['a','b','c','a','c','d','e','b','d','c','a','c'],
'k2':['one','two','three','one','two','three','three','three','one','two','one','two'],
'w':np.random.rand(12),'y':np.random.randn(12)
})
print(data)
data.pivot_table(index='k1',columns='k2')
k1 k2 w y
0 a one 0.505038 -0.692691
1 b two 0.760838 -1.147333
2 c three 0.279918 -0.511096
3 a one 0.361962 0.605746
4 c two 0.605619 0.217253
5 d three 0.708927 1.632609
6 e three 0.760684 -0.099134
7 b three 0.678767 0.814771
8 d one 0.062156 -1.247613
9 c two 0.800672 3.008441
10 a one 0.958991 -0.014311
11 c two 0.943706 0.486200
w y
k2 one three two one three two
k1
a 0.608664 NaN NaN -0.033752 NaN NaN
b NaN 0.678767 0.760838 NaN 0.814771 -1.147333
c NaN 0.279918 0.783332 NaN -0.511096 1.237298
d 0.062156 0.708927 NaN -1.247613 1.632609 NaN
e NaN 0.760684 NaN NaN -0.099134 NaN
由于复制过不来表格 就截屏了 前面遇到过好几次透视表了,groupby出来的都是透视表。
分类汇总求和
交叉表:是一种特殊的透视表,主要用于计算分组频率。使用Pandas提供的crosstab函数可以制作。
crosstab(index, columns ,values=None, rownames=None, colnames=None, aggfunc=None, margins=False,dropna=True,normalize=False )
参数 | 使用说明 |
---|---|
index | 接收string或者list,表示行索引键,没有默认值 |
columns | 接收string或者list,表示列索引键,没有默认值 |
values | 接收array,表示聚合数据,默认为None |
rownames | 表示行分组键名,无默认 |
colnames | 表示列分组键名,无默认 |
aggfunc | 接收函数,表示聚合函数,默认None |
margins | 接收boolean,表示汇总功能开关 |
dropna | 接收boolean,表示删除的全为NaN的列,默认False |
normalize | 接收boolean,表示是否对值进行标准化,默认False |
##交叉表
pd.crosstab(data.k1,data.k2,margins=True)#在边框处增加汇总
k2 one three two All
k1
a 3 0 0 3
b 0 1 1 2
c 0 1 3 4
d 1 1 0 2
e 0 1 0 1
All 4 4 4 12
7.Pandas可视化
Pandas中集成了Matplotlib中的基础组件,绘图便捷。
线形图
线形图一般用于描述两组数据之间的趋势。Pandas库中的Series和DataFrame中都有绘制各类图表的plot方法,默认绘制线形图。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
#线形图Series
obj = pd.Series(np.random.normal(size=10))
obj.plot()
# DataFrame
df = pd.DataFrame({'normal':np.random.normal(size=50),'gamma':np.random.gamma(1, size=50)})
df.plot()
柱状图
柱状图一般用来描述各类别之间的关系。在plot函数中加入参数kind='bar'
,如果类别较多,可以绘制水平柱状图(kind='barh'
)。
在DataFrame中绘制柱状图,对于DataFrame数据而言,每一行的值会成为一组。
# 柱状图 kind='bar'/'barh' 类别多少 rot:标签角度
stu = {'name':['孙尚香','李白','韩信','马克','妲己'],
'sex':['female','male','male','male','female'],
'age':[19,20,22,21,25]
}
df = pd.DataFrame(stu)
print(df['sex'].value_counts())
print(df['sex'].value_counts().plot(kind='bar' ,rot=30))
DataFrame数据对象的柱状图:观察图很显然那个图和数据直接是有很明显的对应关系的,一行是一组图。
# 直接DataFrame作图 类别多 水平柱状图
df = pd.DataFrame(np.random.randint(1,100, size=(4,4)), index=['a','b','c','d'], columns=['I1','I2','I3','I4'])
df.plot(kind='barh')
直方图和密度图
直方图用于频率分布,Y轴为数值或者比率。绘制直方图可以先大致观察数据的大致分布规律。Pandas中的直方图有由hist方法绘制。
核密度估计是对真实密度的估计,其过程是将数据的分布近似为一组核(如正态分布)。通过plot的kind='kde'
进行绘制。
# 直方图【hist bins参数是y轴的值 grid是否有表格】
obj1 = pd.Series(np.random.normal(size=80))
obj1.hist(bins=15, grid=False)
#密度图【kind='kde'】
obj1.plot(kind='kde')
散点图
散点图主要用来表示数据之间的规律,plot(kind='scatter')
#kind = 'scatter' 不能是Sreries 还得给定x与y
df1 = pd.DataFrame(np.arange(10), columns=['A'])
df1['B'] = 2*df1['A']+2
print(df1)
df1.plot(kind='scatter',x='A',y='B')