数据分析篇(六)
- 2019 年 10 月 6 日
- 筆記
join:默认情况是把行索引相同的数据合并到一起
实例:
import pandas as pd
import numpy as np
attr1 = pd.DataFrame(np.arange(12).reshape(3,4),index=list('ABC'),columns=list('abcd'))
attr2 = pd.DataFrame(np.arange(100,106).reshape(2,3),index=list('AB'),columns=list('qwe'))
attr = attr1.join(attr2)
print(attr)
输出:
a b c d q w e
A 0 1 2 3 100.0 101.0 102.0
B 4 5 6 7 103.0 104.0 105.0
C 8 9 10 11 NaN NaN NaN
# 以attr1为主,合并行相同的,不存在就以NaN填充。
# 如果是attr2.join(attr1) 就会以attr2为主。
# 注意:在合并行的时候,列的索引是不能够相同的
merge:通过并列合并
# 这里的merge可以达到和我们数据左连接,右链接,内链接相同的效果。
实例:
attr3 = pd.DataFrame(np.arange(1,13).reshape(3,4),columns=list('aqwe'))
attr4 = pd.DataFrame(np.ones((3,4)),index=list('ABC'),columns=list('abcd'))
attr = attr3.merge(attr4,on='a')
print(attr)
输出:
a q w e b c d
0 1 2 3 4 1.0 1.0 1.0
1 1 2 3 4 1.0 1.0 1.0
2 1 2 3 4 1.0 1.0 1.0
# 参数on表示通过那一列去合并,同时还是以attr3为主
# 在默认情况下,是内链接,也就是取交集
# 取的值是attr3和attr4中a相同的数字的行
# 由于这里的attr4中全是1,所以把attr4中全取出来了,attr3中只取了是1的那一行。
# 内链接完整的想法:attr = attr3.merge(attr4,on='a',how='inner'),和并的方式用how参数
外链接(取并集):
attr = attr3.merge(attr4,on='a',how='outer')
输出结果:
a q w e b c d
0 1 2 3 4 1.0 1.0 1.0
1 1 2 3 4 1.0 1.0 1.0
2 1 2 3 4 1.0 1.0 1.0
3 5 6 7 8 NaN NaN NaN
4 9 10 11 12 NaN NaN NaN
左链接
attr = attr3.merge(attr4,on='a',how='left')
输出和外连接一样,之所以一样,是因为我们的数据
右链接
输出结果:
a q w e b c d
0 1 2 3 4 1.0 1.0 1.0
1 1 2 3 4 1.0 1.0 1.0
2 1 2 3 4 1.0 1.0 1.0
# 数据不全会用NaN补全。
分组聚合
groupby:分组
dict = {'name':['张三','李四','王五'],'age':[18,20,27],'tel':[10010,10086,1008611],'sex':['男','女','男']}
attr1 = pd.DataFrame(dict)
# 按照性别分组
attr = attr1.groupby(by='sex')
print(attr) # DataFrameGroupBy类型
# 需要遍历输出
for i,item in attr:
print(i)
print('——')
print(item)
输出:
女
——
name age tel sex
1 李四 20 10086 女
男
——
name age tel sex
0 张三 18 10010 男
2 王五 27 1008611 男
# 按照性别将男女分开。
如果只想取性别为男的数据:
attr1[attr1['sex']=='男']
# 分组是可以根据多个字段分组的,号隔开即可。
聚合函数
count():
实例:
sex_by_count = attr.count()
print(sex_by_count )
输出:
name age tel
sex
女 1 1 1
男 2 2 2
也就是计算了根据分组后每个组的数量。
sum:非NaN的和
mean:非NaN的平均值
median:非NaN的的算术中位数
std,var : 标准差和方差
min,max:非NaN的的最小值和最大值
索引的方法和属性
index:
实例:
print(sex_by_count.index)
输出:
Index(['女', '男'], dtype='object', name='sex')
改变索引:
sex_by_count.index = list('ab')
或者:
sex_by_count.index = ['a','b']
print(sex_by_count.index)
变成:
name age tel
a 1 1 1
b 2 2 2
将索引替换成了a,b
reindex:
print(sex_by_count.reindex(list('ac')))
输出:
name age tel
a 1.0 1.0 1.0
c NaN NaN NaN
当存在索引为a的行,输出,不存在输出NaN填充
指定某一列为索引
# 指定name为索引值
print(sex_by_count.set_index("name"))
输出:
age tel
name
1 1 1
2 2 2
# 会发现name值作为索引后,后面就没有值了,我们想让他显示:
sex_by_count.set_index("name",drop=False)
输出:
name age tel
name
1 1 1 1
2 2 2 2
当我们用name做索引的时候,那么索引中存在相同的值是不合理的。
# 查看某列不相同的数量;
sex_by_count.unique()
# 去重复
sex_by_count.set_index("name").index.unique()
# 设置多个索引值
sex_by_count.set_index(["name",'age'],drop=False)
# 当我们有多个索引的时候,怎么操作?
复合索引
实例:
dict = {'name':['张三','李四','王五'],'age':[18,20,27],'tel':[10010,10086,1008611],'sex':['男','女','男']}
attr1 = pd.DataFrame(dict)
# 设置sex和name为索引值
attr2 = attr1.set_index(["sex","name"])
# 取性别为男的张三的年龄
attr3 = attr2['age']
print(attr3['男']['张三'])
# 取性别为男的人的数据
print(attr3['男'])
# 但是如果我们交换索引位置
attr4 = attr1.set_index(["name","sex"])
# 此时如果我们还是只想取男生的年龄,用之前的操作就不行了
# 我们需要这样写
attr5 = attr4['age']
attr6 = attr5.swaplevel()
print(attr6['男'])
# 如果我们用loc取值
attr3.loc['男'].loc['张三']
处理时间
自动生成时间:
实例:
attr = pd.date_range(start='20170101',end='20180101',freq='D')
print(attr)
输出:
DatetimeIndex(['2017-01-01', '2017-01-02', '2017-01-03', '2017-01-04',
'2017-01-05', '2017-01-06', '2017-01-07', '2017-01-08',
'2017-01-09', '2017-01-10',
…
'2017-12-23', '2017-12-24', '2017-12-25', '2017-12-26',
'2017-12-27', '2017-12-28', '2017-12-29', '2017-12-30',
'2017-12-31', '2018-01-01'],
dtype='datetime64[ns]', length=366, freq='D')
# atart 开始时间, end结束时间,freq : D是以天为单位,10D就是以10天为单位,M就是月等等
其他:
B:工作日
H:小时
T或min:分
S:秒
L或ms:毫秒
U:微妙
BM:每月最后一个工作日
MS:每月第一天
BMS:每月第一个工作日
# 时间是可以作为索引的
# 以20天为一个间隔
attr = pd.date_range(start='20170101',end='20180101',freq='20D')
输出:
DatetimeIndex(['2017-01-01', '2017-01-21', '2017-02-10', '2017-03-02',
'2017-03-22', '2017-04-11', '2017-05-01', '2017-05-21',
'2017-06-10', '2017-06-30', '2017-07-20', '2017-08-09',
'2017-08-29', '2017-09-18', '2017-10-08', '2017-10-28',
'2017-11-17', '2017-12-07', '2017-12-27'],
dtype='datetime64[ns]', freq='20D')
# 输出前10个 不能有结束时间
attr = pd.date_range(start='20170101',periods=10,freq='20D')
# 将字符串转化为时间
pd.to_datetime(时间列,format='')
# format 是格式化,常用的格式符号请看基础篇中的time模块。
pandas重采样
重采样:指将时间序列从一个频率转化为另一个频率的过程。
降采样:高频率转化为低频率(比如将一个精确到秒的时间转化为只有年月日)
升采样:低频率转化为高频率(与上面相反)
我们需要用resample来实现频率转换。
比如:
# 生成100行数据,索引为100个从2017-01-01开始每一个加一个小时,并且精确到秒
attr = pd.DataFrame(np.arange(100).reshape((100,1)),index=pd.date_range(start='20170101',periods=100,freq='3600S'))
# 降采样
attr1 = attr.resample('D')
# 取每天的平均值。
print(attr1.mean())