python数据分析 | Pandas全面介绍及使用(3)

import pandas as pd
import numpy as np

1 索引与分层索引

1.1 分层索引的引出

(1)索引

  • 查看索引:df.index
  • 指定索引:df.index = [,] 列表,个数必须一致
  • 重置索引:df.reindex([,]) 无需个数一致
  • 指定某一列作为index:df.set_index(“M”,drop=False)
  • 返回index的唯一值:df.set_index(“M”).index.unique()
  • df.reset_index():将分层索引层级移动到列中

(2)分层索引
分层索引是Pandas一个重要的特性,允许在一个轴上拥有多个所以层级。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KZWn0TeA-1599888889835)(attachment:image.png)]

df = pd.DataFrame(np.arange(12).reshape(3,4),index=list("ABC"),columns=list("MNOP"))
df
# df.index[1] = "D"   # 报错,索引不能单独赋值修改
df.reindex(["A","D"])  # 仅留下A,D列
"""
df.set_index(keys,drop=True)
drop=True 指定该列为索引 并且删除该列数值
"""
df.set_index("M")
# df.set_index("M",drop=False)
"""
当index重复后
返回的index唯一值
"""
# 将df中的4赋值为8
df.loc["B","M"] = 8
print(df,'\n','----------------------')
# 设置M列为索引
df1 = df.set_index("M")   # M列有2个8的索引

"""
当index重复后
返回的index唯一值
"""
# 设置M列为索引
df1 = df.set_index("M")
# 取出索引为8的行
print(df1.loc[8,:],'\n','------------------------')  
# 打印出不重复的索引
print(df1.index.unique(),'\n','------------------------')
df2 = df.set_index(["M","N"])
df2    # 注意:两行的index都是8,重复,所以省略了,此处就是0,8分层索引(或者就是分组索引)

在这里插入图片描述

"""具体例子"""
df = pd.DataFrame({
    'a':range(7),
    'b':range(7,0,-1),
    'c':['one','one','one','two','two','two','two'],
    'd':list("hjklmno")
})
df

在这里插入图片描述

df4 = df.set_index(["c","d"])
df4  # 可以理解为c是大类,d是小类

在这里插入图片描述

1.2 分层索引的一些应用

"""
df4.index:MultiIndex  多层索引
df4.index:MultiIndex
- levels 表示层级
- codes  层级对应的位置索引
- names  索引名称
"""
# 多层索引:MultiIndex
df4.index
"""
分层索引DataFrame取值
"""
df4.loc["one"]   # 选择one这块元素

# 选择one two 整块数据
df4.loc["one":"two"]
df4.loc[["one","two"]]

# 选出j这行
# df4.loc["one"]["j"]    # 报错

df4.loc["one"].loc["j"]
# df4.loc["one","j"]     # 注意:loc[外层索引,内层索引]

# 取 one 块 1
df4.loc["one"].loc["j","a"]
df4.loc["one"].loc["j"]["a"]
df4.loc["one","j"]["a"]
"""
Series取值
"""
df5 = df4["a"]
df5
# 取one这块
df5["one"]

# 选择one two 整块数据
df5["one":"two"]
df5[["one","two"]]

# 取1
df5["one"]["j"]
"""其他level层级操作"""
df4.sort_index(level="c",ascending=False)   # 指定1层(two、one)进行降序
df4.sum(level="c")  # 指定c层级求和
df4.reset_index(drop=False)  # 重新设置索引为默认索引
# df4.reset_index(drop=True)  # 重新设置索引为默认索引,drop为True,把c这一列丢弃

2 数据合并

数据合并也就是说将多个数据集拼接在一起,但是合并的方式主要分为:pandas.merge,pandas.concat,df.join。以下,我们来详细的介绍。

2.1 df_l.join

df_l.join(df_r,how="left") 默认情况下是把行索引相同的数据合并到一起,以df_l为主。

df1 = pd.DataFrame(np.arange(12).reshape(3,4),index=list("ABC"),columns=list("DEFG"))
df2 = pd.DataFrame(np.arange(6).reshape(2,3),index=list("AB"),columns=list("WXY"))
print(df1,'\n',df2)
"""
df1.join(other,how="left")
- other      连接的数组
- how="left" 相当于以左边的df1为主 
"""
print(df1.join(df2))  # df2补充了W,X,Y
print(df2.join(df1))  # df1只保存AB两列

2.2 pd.merge

pd.merge(df_l,df_r) 根据一个或多个键将行进行连接

  • how: 指定拼接方式;inner,outer,left,right。默认是inner
  • on : 需要连接的列名。注:必须是公共列
  • left_on : 左边数组中用作连接的列
  • right_on : 右边数组中用作连接的列
df1 = pd.DataFrame(np.arange(12).reshape(3,4),index=list("ABC"),columns=list("DEFG"))
df2 = pd.DataFrame(np.arange(10).reshape(2,5),index=list("AB"),columns=list("WXYZL"))

print(df1)
print(df2)
# 没有公共列 报错
# df1.merge(df2)
df3 = pd.DataFrame(np.arange(6).reshape(2,3),index=list("AB"),columns=list("XYZ"))
df4 = pd.DataFrame(np.arange(6).reshape(3,2),index=list("ABC"),columns=list("WZ"))

print(df3)
print(df4)
"""
当公共列 有公共元素时
默认以公共元素拼接
"""
pd.merge(df3,df4)    # z列中公共5进行拼接
"""
公共z列中 不含有公共元素的时候。直接为空
"""
df4.loc["C","Z"] = 6
print(df4)

pd.merge(df3,df4)
"""
公共z列 有多个共同元素,多个共同元素进行合并,合并后有两行
"""
df4.loc["A":"B","Z"] = [2,5]
print(df4)

pd.merge(df3,df4)
"""
指定拼接方式?
- how:left,right,inner,outer 指定拼接方式
- on:指定列进行连接,但注意:该列需要时公共列
"""
# pd.merge(df3,df4,how="left")   # 左边 不会删除掉 df3任何值
# pd.merge(df3,df4,how="right")  # 右边  不会删除掉 df4任何值
pd.merge(df3,df4,how="outer")  # 并集  不会删除掉 df3,df4任何值
"""
left_on:指定左边的列作为连接的列
right_on:指定右边的列作为连接的列
"""
print(df3)
print(df4)

# df3 中的"Y" 与 df4 中的 "W" 交集为4 相当于两边的最后一行进行连接
df3.merge(df4,left_on="Y",right_on="W")

2.3 pd.concat

  • pd.concat((df_l,df_r),axis=0) 使对象在轴向上进行黏合或"堆叠"
df1 = pd.DataFrame(np.arange(12).reshape(3,4),index=list("ABC"),columns=list("QWER"))
df2 = pd.DataFrame(np.arange(15).reshape(3,5),index=list("ABC"),columns=list("ZXCVB"))
# 行索引一致,进行列的堆叠
pd.concat((df1,df2),axis=1)

在这里插入图片描述

# 行的堆叠
df3 = df1.T
df4 = df2.T
print(df3)
print(df4)
pd.concat((df3,df4))

在这里插入图片描述

3 数据分组与聚合

数据包含在Series、DataFrame数据结构中,可以根据一个或多个键分离到各个组中。分组操作之后,一个函数就可以应用到各个组中,产生新的值。如下图则是简单的分组聚合过程
在这里插入图片描述

3.1 分组

(1)语法:`df.groupby(‘key’)

df1 = pd.DataFrame(
    {
        "names":["菲菲","小可爱","mia","牛哥","老王","mia","狼人","药水哥","药水哥"],
        "classes":["一班","二班","三班"]*3,
        "grades":np.random.randint(60,100,size=9)
    }
)
df1

在这里插入图片描述

# 以班级进行分组
g = df1.groupby(by="classes")   # 返回:DataFrameGroupBy的对象,可迭代的
g # <pandas.core.groupby.generic.DataFrameGroupBy object at 0x000001C6DDEDFA48>  利用for循环 取值
# 遍历 DataFrameGroupBy 的对象
for i in g:
    print(i)       # 输出的结果:(组名(g_name),每个组(group)的数据) 为元组
    print("-"*50)
for g_name,group in g:
    print(g_name)      # 分组的组名:一班、三班、二班
    print(group)       # 数据块 
    print(type(group)) # DataFrame
    print("-"*50)

3.2 聚合

(1)语法:df.groupby(by="分类属性")[聚合属性].聚合函数

3.2.1 自带的聚合函数

常用的聚合函数:
在这里插入图片描述

"""自带的聚合函数"""
# 了解每个班级的均值   分组+聚合 
df1.groupby(by="classes")["grades"].mean()

3.2.2 自定义的聚合函数

"""自定义的聚合函数:单个自定义函数"""
# 需求:
# - 计算每个班级之间的差值:一班的最大值-一班的最小值

# 实现:
# - 定义一个函数
# - 分组之后通过agg,aggregate函数聚合
def class_ptp(x):
    return np.max(x) - np.min(x)
df1.groupby(by="classes")["grades"].agg(class_ptp)  # agg函数聚合,请注意这里定义的函数是引用
# df1.groupby(by="classes")["grades"].aggregate(class_ptp)  # aggregate函数聚合,请注意这里定义的函数是引用
"""自定义的聚合函数:多个自定义函数"""
# 需求:显示 各班级的极差 最大值 最小值
# 实现:agg,aggregate都可以传入列表

agg_li = [np.ptp,np.max,np.min]
df1.groupby(by="classes")["grades"].agg(agg_li)

3.2.3 分组块上的应用函数

"""
需求:
每个班级的成绩,进行降序
实现:
(1)以班级分组:每组都是df
(2)apply()将每组应用到函数上
"""
def sort_df(df):
    return df.sort_values(by="grades",ascending = False)
df1.groupby(by="classes").apply(sort_df)   # 注意此处是引用

在这里插入图片描述

3.2.4 其它的分组形式

  • 字典
  • series
  • 函数
"""字典"""
df2 = pd.DataFrame(
    np.random.randint(60,100,size=(5,3)),
    index=["菲菲","小可爱","mia","牛哥","老王"],
    columns=["语文","数学","英语"]
)
df2
# 定义字典
g_dic = {"菲菲":"一班","小可爱":"一班","mia":"二班","牛哥":"三班"}

# 求各班班级成绩均值,实际上:通过名字将其班级关系联系起来
df2.groupby(by=g_dic).mean()

在这里插入图片描述

"""series"""
s = pd.Series(g_dic)  # 将字典转为series格式
df2.groupby(by=s).mean()
"""函数"""
# If ``by`` is a function, it's called on each value of the object's  index.
# 以班级同学姓名的长度进行分组  注意:function时:分组的names为索引
df3 = df1.set_index("names")  # 设置names为索引
df3.groupby(len).count()      # 以名字的长度进行分组,求个数  

4 时间序列

(1)介绍:时间序列数据在很多领域都是重要的结构化数据形式,比如:金融,神经科学,生态学,物理学。在多个时间点观测的数据形成了时间序列。时间序列可以是固定频率的,也可以是不规则的。
(2)常见使用:时间戳、固定的时间区间、时间间隔

  • 时间戳:指格林威治时间自1970年1月du1日(00:00:00 GMT)至当前时间的总秒数。通zhi俗的讲,时间戳是一份能够表示一份数据在一dao个特定时间点已经存在的完整的可验证的数据。
  • 固定的时间区间:字面意思 年月日分时秒
  • 时间间隔:字面意思

4.1 时间序列基础

(1)介绍:Pandas中的基础时间序列种类是由时间戳索引的Series,在Pandas外部通常表示为Python字符串或datetime对象。
(2)注意

  • datetime对象可作为索引,时间序列DatetimeIndex
  • <M8[ns]类型为纳秒级时间戳
  • 时间序列里面每个元素为Timestamp对象
"""导入模块"""
import pandas as pd
import numpy as np
from datetime import datetime
# datetime对象列表
dates = [datetime(2020,9,1),datetime(2020,9,2),datetime(2020,9,3),datetime(2020,9,4)]

# datetime对象列表 作为 索引
ts = pd.Series(np.random.randint(1,10,size=4),index=dates)
ts
ts.index    # DatetimeIndex 时间序列索引  datetime对象可以被放入DatetimeIndex中 就是时间序列索引
ts[::2]+ts   # 运算,会自动对齐,缺失的补充为nan
ts.index.dtype  # dtype('<M8[ns]') 纳秒级的分辨率下存储时间戳
ts.index[0]     # DatetimeIndex每个值时 Timestamp对象

4.2 生成时间序列函数

语法: pd.date_range(start=None,end=None,periods=None,freq=None,tz=None,normalize=False)

  • start 起始时间
  • end 结束时间
  • periods 固定时期
  • freq 日期偏移量(频率)
  • normalize 标准化为0的时间戳
    常用频率设置如下
    在这里插入图片描述
    具体可参考:https://pandas.pydata.org/pandas-docs/stable/user_guide/timeseries.html#timeseries-offset-aliases
# 生成20200101至20200201时间区间  默认的频率D-->一天
pd.date_range(start="20200101",end="20200201")
# 生成20200101至20200201时间区间  频率-->10天-->10D
pd.date_range(start="20200101",end="20200201",freq="10D")
# 4小时-->4h
pd.date_range(start="20200101",end="20200201",freq="4h")
# 一个半小时-->1h30min 或者 1.5H
pd.date_range(start="20200101",end="20200201",freq="1h30min")
# 生成20200101至20200201时间区间  等分划分区间:periods=5
pd.date_range(start="20200101",end="20200201",periods=5)
# 生成20200101  等分划分区间:periods=5  默认的freq:1D
pd.date_range(start="20200101",periods=5)
# normalize 标准化为0
pd.date_range(start="2020-01-01 12:59:59",periods=5,normalize=True)

4.3 时间序列的索引及选择数据

"""series"""
ts = pd.Series(np.random.randint(1,100,size=600),index=pd.date_range("20190101",periods=600))
ts
# 选择2020的数据
print(ts["2020"] )       # 时间序列索引 选择年份
# 选择2020 1月数据
print(ts["2020 01"] )     # 注意:标准的时间格式 2020 01、 2020/01、 2020-01都可
# 选择2020 1 10 - 2020 1 20 切片方法实现
print(ts["2020 1 10":"2020 1 20"])
"""DataFrame"""
df_ts = pd.DataFrame(np.arange(500),index=pd.date_range("20190101",periods=500))
df_ts
print(df_ts.loc["2020"])  # loc选择index标签 ,选择2020年
print(df_ts.loc["2020 05 01":,:]) # loc选择index标签 ,行,列 
"""
含有重复索引的时间序列
• df.indexis_unique :检查索引是否唯一
"""
dates = [datetime(2020,9,10),datetime(2020,9,9),datetime(2020,9,10),datetime(2020,9,10)]
dup_ts = pd.Series(np.arange(4),index=dates)
print(dup_ts)
# 检查索引是否唯一
print(dup_ts.index.is_unique)   # 重复:False
# 索引非唯一 可以分组聚合
print(dup_ts.groupby(level=0).mean())

4.4 移位日期

  • "移位"指的是将日期按时间向前移动或向后移动
  • Series和DataFrame都有一个shift方法用于进行简单的前向或后向移位 而不改变索引
ts = pd.Series(np.random.randint(1,100,size=600),index=pd.date_range("20190101",periods=600))
ts
"""
索引不变,数值移位:索引并不发现变化 是数值移位引入缺失值
"""
ts.shift(2)   # 向前移位 2 等同于 滞后2期  把2020.8.1日期移动到2020.8.3
ts.shift(-2)  # 向后移位 2 等同于 前置2期  把2020.8.3日期移动到2020.8.2

# 百分比 pct_change  (后一天-前一天)/前一天 -->后一天/前一天 - 1 
ts/ts.shift(1)-1
ts.pct_change()
"""
索引移位,数值移位:时间序列整个移位,指定频率即可
"""
ts.shift(2,freq="D")

4.5 重采样

(1)介绍:指的是将时间序列从一个频率转化为另一个频率进行处理的过程,将高频率数据转化为低频率数据为降采样低频率转化为高频率为升采样

ts = pd.DataFrame(np.random.randint(100,200,size=100),index=pd.date_range(start="20200101",periods=100))
ts
"""
降采样
"""
# 降采样 频率D-->M     降采样 类似 于 分组聚合
ts.resample("M").sum() 
"""
升采样 低频-->高频
"""
ts_tz = pd.DataFrame(np.random.randint(2000,5000,size=(4,4)),index=pd.date_range(start="20200801",freq="10D",periods=4),columns=["北","上","广","深"])
ts_tz
# 10D-->D
ts_tz.resample("D").asfreq()   # 转换为高频  缺失值为nan
# 填充缺失值
ts_tz.resample("D").ffill()   # 插值填充  缺失值填充为前一值
"""如果日期为格式不为datatime,如何转为datetime"""
df = pd.DataFrame(np.random.randint(1000,4000,size=(4,4)),index=[20200101,20200102,20200103,20200104],columns=["北京","上海","广州","深圳"])
print(df.index.dtype)
df
"""
转为时间序列
- 改变该列的类型 -->int64转为datetime
"""
# 重置索引
df.reset_index(inplace=True)
# df["index"] = pd.to_datetime(df["index"])   # 不定义格式会转为时间戳 1970-01-01 00:00:00.020200101
df["index"] = pd.to_datetime(df["index"],format="%Y%m%d")
df
df.set_index("index",inplace=True)
df.loc["2020"]  # 索引变为datetime格式,可通过loc得到一定时间范围数据
df.loc["2020"]

5 pandas绘图

Series跟DataFrame都有plot属性,用来绘制基本图形。默认情况下,绘制的是折线图

import pandas as pd
import matplotlib.pyplot as plt
# 导入数据
iris_data = pd.read_csv("iris.csv")
iris_data

在这里插入图片描述

iris_data.plot()
plt.show()

在这里插入图片描述

"""
直观的比较每种花的长宽的均值(直观的呈现)
"""
iris_data.groupby(by="Name").mean().plot(kind="bar")
plt.show()

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值