Pandas

1.Pandas支持读取的文件类型

数据类型说明Pandas读取方法
csv、tsv、txt逗号分隔、tab分割的纯文本文件pd.read_csv
excel微软xls或者xlsx文件pd.read_excel
mysql关系型数据库pd.read_sql

2.文件读取

1.读取纯文本文件
  • 读取csv,使用默认的标题行、逗号分隔符
    import pandas as pd
    
    # 读取文件
    fpath = './data/ratings.csv'
    ratings = pd.read_csv(fpath)
    
    • fpath:文件路径
    • sep:数据分隔符
    • header
    • names:某些数据没有表头,可以自定义列名,数组类型
  • 查看前几行数据,默认前5行
    ratings.head()
    
  • 查看数据形状
    ratings.shape
    
  • 查看列索引
    ratings.columns
    
  • 查看行索引
    ratings.index
    
  • 查看每列的数据类型
    ratings.dtypes
    
2.读取excel文件
import pandas as pd
	
fpath = './data/access_pvuv.xlsx'
ratings = pd.read_excel(fpath)

在这里插入图片描述

3.读取mysql

在这里插入图片描述

import pymysql
import pandas as pd

conn = pymysql.connect(
	host="127.0.0.1",
	user="admin",
	password="password",
	database="test",
	charset="utf8"
)

mysql_page = pd.read_sql("select * from crazyant_pvuv", conn=conn)

3.Pandas数据结构

1.DataFrame:二维数据,整个表格,多行多列)

在这里插入图片描述

1.定义
  • DataFrame是一个表格型的数据结构
  • 每列可以是不同的值类型(数值、字符串、布尔值等)
  • 既有行索引index,也有列索引columns
  • 可以被看作是由Series组成的字典
2.创建DataFrame常用方法
  • 1.读取纯文本文件

  • 2.读取excel文件

  • 3.读取mysql数据库

  • 4.从数据源创建

    import pandas as pd
    
    data = {
        "state": ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada'],
        "year": [2000, 2001, 2002, 2001, 2002],
        "pop": [1.5, 1.7, 3.6, 2.4, 2.9]
    }
    
    df = pd.DataFrame(data)
    
    	state	year	pop
    0	Ohio	2000	1.5
    1	Ohio	2001	1.7
    2	Ohio	2002	3.6
    3	Nevada	2001	2.4
    4	Nevada	2002	2.9
    

2.Series:一维数据,一行或一列

1.定义
  • Series是一种类似于一维数组的对象,类似于python字典,它由一组数据(可以是不同数据类型)以及一组与之相关的数据标签(即索引)组成
2.创建Series常用方法
  • 1.使用列表数据生成一个最简单的Series

    import pandas as pd
    s1 = pd.Series([1, 'a', 5, True, [1]])
    
    0       1
    1       a
    2       5
    3    True
    4     [1]
    dtype: object
    
    • 获取索引
      s1.index  # RangeIndex(start=0, stop=5, step=1)
      
    • 获取数据
      s1.values  # array([1, 'a', 5, True, list([1])], dtype=object)
      
  • 2.创建一个具有标签索引的Series

    import pandas as pd
    s2 = pd.Series([1, 'a', 5, True, [1]], index=['a', 'b', 'c', 'd', 'e'])
    
    a       1
    b       a
    c       5
    d    True
    e     [1]
    dtype: object
    
    • 根据索引取单个值
      s2['a']   # 1
      type(s2['a'])  # int
      
    • 根据索引取多个值
      s2[['a', 'b']]
      '''
      a    1
      b    a
      dtype: object
      '''
      type(s2[['a', 'b']])  # pandas.core.series.Series
      
  • 2.使用Python字典创建Series

    import pandas as pd
    sdata = {'Ohio': 35000, 'Texas': 72000, 'Oregon': 16000, 'Utah': 5000}
    s3 = pd.Series(sdata)
    
    Ohio      35000
    Texas     72000
    Oregon    16000
    Utah       5000
    dtype: int64
    

3.从DataFrame中查询出Series

1.概念
  • 1.如果只查询一行、一列,返回的是pd.Series
  • 2.如果查询多行、多列,返回的是pd.DataFrame
2.演示
  • 获取state索引列数据
    import pandas as pd
    data = {
        "state": ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada'],
        "year": [2000, 2001, 2002, 2001, 2002],
        "pop": [1.5, 1.7, 3.6, 2.4, 2.9]
    }
    
    df = pd.DataFrame(data)
    type(df['state'])  # pandas.core.series.Series
    # 查询第一行
    # type(df.loc[0])  # pandas.core.series.Series
    
  • 获取state、year索引列数据
    import pandas as pd
    
    df[['state', 'year']]
    '''
    	state	year
    0	Ohio	2000
    1	Ohio	2001
    2	Ohio	2002
    3	Nevada	2001
    4	Nevada	2002
    '''
    
    type(df[['state', 'year']])  # pandas.core.frame.DataFrame
    
    
    # 查询前两行
    # type(df.loc[0: 1])  # pandas.core.frame.DataFrame
    # df.loc[0: 1]  # 包含尾部索引
    '''
    state	year	pop
    0	Ohio	2000	1.5
    1	Ohio	2001	1.7
    '''
    

4.Pandas数据查询

1.df.loc

1.定义
  • 根据行、列的标签查询
2.示例演示(以下方法行列均适应)
  • 1.数据读取

    df.read_csv('./data/beijing_tianqi_2018.csv')
    
  • 2.设置索引为日期,方便按日期筛选

    df.set_index('year', drop=True, append=False, inplace=False, verify_integrity=False)
    
    • drop:是否删除作为索引使用的列,默认删除
    • append:将序列添加到索引中,形成多级序列
    • inplace:是否返回在原序列上进行修改,默认否,返回一个新的序列
    • verify_integrity:检查索引是否重复。默认是False
  • 3.数据预处理(将温度的后缀°C去掉)

    # 所有行,bWendu列       bWendu列转为字符串,去除°C,然后转换为整形
    df.loc[:, "bWendu"] = df["bWendu"].str.replace("°C", "").astype("int32")
    df.loc[:, "yWendu"] = df["yWendu"].str.replace("°C", "").astype("int32")
    
  • 4.使用单个label值查询数据

    # 单元格 数据,得到一个具体的值
    df.loc['2018-01-03', 'bWendu']
    
  • 5.使用值列表批量查询

    # 一行两列 数据,得到一个Series,即:1月3日的最高温度和最低温度
    df.loc['2018-01-03', ['bWendu', 'yWendu']]
    
    # 一列两行 数据,得到一个Series,即:1月3日和1月4日的最高温度
    df.loc[['2018-01-03', '2018-01-04'], 'bWendu']
    
    # 两行两列 数据,得到一个DataFrame
    df.loc[['2018-01-03', '2018-01-04'], ['bWendu', 'yWendu']]
    
  • 6.使用数值区间进行范围查询(区间包含开始,也包含结束,和列表有所不同)

    # 行index区间
    # 获取1月3号到1月6号的最高温度
    df.loc['2018-01-03':'2018-01-06', 'bWendu']
    
    # 列index区间
    # 获取1月3号最高温度到风向的所有列
    df.loc['2018-01-03', 'bWendu':'fengxiang']
    
    # 行列都按区间查询
    df.loc['2018-01-03':'2018-01-06', 'bWendu':'fengxiang']
    
  • 7.使用条件表达式查询

    # 查询最高温度大于10°C的天气数据
    df.loc[df['bWendu'] > 10, :]
    
    # 查询最高温度小于30°,并且最低温度大于15°,并且是晴天,并且天气为优的数据
    df.loc[(df['bWendu'] < 30) & df['bWendu'] > 15) & df['tianqi'] == '晴') & df['aqiLevel'] == 1), :]
    
  • 8.调用函数查询

    def query_data(df):
    	return df.index.str.startswith('2018-09') & df['sqiLevel'] == 1
    
    # 查询9月份,空气质量为优的数据
    df.loc[query_data, :]
    

2.df.ilock

1定义
  • 根据行列的数字位置查询

3.df.where

1.定义
  • 根据条件替换行或列中的值。如果满足条件,保持原来的值,不满足条件则替换为其他值。默认替换为NaN,也可以指定特殊值。
    DataFrame.where(cond, other=nan, inplace=False, axis=None, level=None, errors='raise', try_cast=False, raise_on_error=None)
    
    • cond:布尔条件,如果 cond 为真,保持原来的值,否则替换为other
    • other:替换的特殊值
    • inplace:inplace为真则在原数据上操作,为False则在原数据的copy上操作
    • axis:行或列

4.df.query

1.定义
  • 根据条件过滤出符合的行或列

5.Pandas新增数据列

1.直接赋值

  • 类似于字典新增一个key
    # 给所有行,增加一个温差列   值为最高温度减去最低温度
    # df["bWendu"]是一个Series,两个Series相减,最终返回还是一个Series
    df.loc[:, "wencha"] = df["bWendu"] - df["yWendu"]
    

2.df.apply

  • 沿着axis轴,将一个Series传递给一个函数,该函数对传递的Series进行处理,返回一个新的Series

  • axis=0代表横轴,即二维坐标系中的x轴,也就是行

  • axis=1代表纵轴,即二维坐标系中的y轴,也就是列

    # 添加一列温度类型(如果最高温度大于33°就是高温;低于-10°就行就是低温;否则是常温)
    
    def get_wendu_type(x):
    	if x["bWendu"] > 30:
    		return "高温"
    	if x["yWendu"] < -10:
    		return "低温"
    	return "常温"
    
    df[:, "wendu_type"] = df.apply(get_wendu_type, axis=1)
    
    # 对温度类型进行统计
    df["wendu_type"].value_counts()
    

3.df.assign

  • 将某一列数据,作为函数参数传入,该函数返回一个新的对象,包含新的列和原来的列
  • 可以同时新增多列
    # 新增最高温度和最低温度对应的华氏温度列
    df.assign(
    	# 新增的列名                  x代表df
    	yWendu_huashi = lambda x : x["yWendu"] * 9 / 5 + 32
    	bWendu_huashi = lambda x : x["bWendu"] * 9 / 5 + 32
    )
    

4.按条件选择分组分别赋值

  • 按条件先选择数据,然后对这部分数据进行赋值新列
  • 将原数据按照温差进行分组(高温-低温>10,则认为温差大)
    # 创建一个新列
    df["wencha_type"] = ""
    # 按条件选择,然后赋值给上面创建的列
    df.loc[df["bWendu"] - df["yWendu"] > 10, "wencha_type"] = "温差大"
    df.loc[df["bWendu"] - df["yWendu"] <= 10, "wencha_type"] = "温差正常"
    

6.Pandas数据统计函数

1.汇总类统计

1.一下子提取所有数字列统计结果
df.describe()

在这里插入图片描述

2.查看平均值
  • 查看高温平均值
df["bWendu"].mean()
3.查看最大值
  • 查看最高温
df["bWendu"].max()
4.查看最小值
  • 查看最低温
df["yWendu"].min()

2.唯一去重和按值计数

1.唯一性去重(一般用于枚举、分类列)
  • 风向去重
    df['fengxiang'].unique()
    
  • 天气去重
    df['tianqi'].unique()
    
  • 风力去重
    df['fengli'].unique()
    
2.按值计数
  • 统计每个风向出现的次数
    df['fengxiang'].value_counts()
    

3.相关系数和协方差

1.定义
1.协方差
  • 1.衡量同向反向程度
  • 2.如果协方差为正,说明X、Y同向变化,协方差越大说明同向程度越高
  • 3.如果协方差为负,说明X、Y反向变化,协方差越小说明反向程度越高
2.相关系数
  • 1.衡量相似程度
  • 2.当他们相关系数为1时,说明两个变量变化时的正相似度最大
  • 3.当他们相关洗漱为-1时,说明两个变量变化时的反相似度最大
2.用途
  • 1.两只股票,是不是同涨同跌?程度多大?正常关还是负相关
  • 2.产品销量的波动,跟哪些因素正相关、负相关、程度有多大
3.编码
  • 协方差矩阵
    df.cov()
    

在这里插入图片描述

  • 相关系数矩阵
    # 可以看出空气质量指数aqi和空气质量等级aqiLevel相关性为0.94,非常的相关
    df.corr()
    

在这里插入图片描述

  • 单独查看
    # 空气质量和最高温度的相关系数
    df["aqi"].corr(df["bWendu"])  # 0.077067
    
    # 空气质量和最低温度的相关系数
    df["aqi"].corr(df["yWendu"])  # 0.026513
    
    # 空气质量和温差的相关系数
    df["aqi"].corr(df["bWendu"] - df["yWendu"])  # 0.216522
    

7.Pandas缺失值处理

1.isnullnotnull:检测是否是空值,可用于DataFrameSeries

2.dropna:丢弃、删除缺失值

  • axis:删除行还是列,{0 or ‘index’, 1 or columns},default 0
  • how:如果等于any,则任何值为空都删除,如果等于all则所有值都为空才删除
  • inplace:如果为True则修改当前df,否则返回新的df,默认返回新的

3.fillna:填充空值

  • value:用于填充的值,可以是单个值,或者字典(key是列名,value是值)
  • method:等于ffill,使用前一个不为空的值填充forward fill,等于bfill,使后一个不为空的值填充backword fill
  • axis:按行还是列填充,{0 or ‘index’, 1 or columns}
  • inplace:如果为True则修改当前df,否则返回新的df,默认返回新的

4.事例演示

1.数据如下

在这里插入图片描述

2.读取excel
# 跳过前两行读取
studf = pd.read_excel('./data/study_excel.xlsx', skiprows=2)

在这里插入图片描述

3.检测空值
studf.isnull()

在这里插入图片描述

3.1.单列检测空值
studf["分数"].isnull()
3.2.筛选没有空分数的所有行
studf.loc[studf["分数"].notnull(), :]

在这里插入图片描述

4.删除掉全是空值的列
# 在元数据基础上删除全是空值的列
studf.dropna(axis="columns", how="all", inplace=True)

在这里插入图片描述

5.删除掉全是空值的行
# 在元数据基础上删除全是空值的行
studf.dropna(axis="index", how="all", inplace=True)

在这里插入图片描述

6.将分数列为空的填充为0分
studf.fillna({"分数": 0})
# 等同于
# studf.loc[:, "分数"] = studf['分数'].fillna(0)

在这里插入图片描述

7.将姓名的缺失值填充
# 使用前一个不为空的值进行填充
studf.loc[:, "姓名"] = studf["姓名"].fillna(method="ffill")

在这里插入图片描述

8.将清洗好的excel保存
# index=False:去除索引列
studf.to_excel('./data/result_student.xlsx', index=False)

在这里插入图片描述

8.SettingWithCopyWarning告警处理

1.原数据如下

在这里插入图片描述

2.复现问题
  • 1.只选出3月份的数据,用于分析
    condition = df["ymd"].str.startswith("2018-03")
    # 设置温差列(报错)
    df[condition]["wencha"] = df["bWendu"] - df["yWendu"]
    # 查看结果
    df[condition].head()
    
    在这里插入图片描述
    在这里插入图片描述
3.原因
  • 发出告警的代码:df[condition]["wencha"] = df["bWendu"] - df["yWendu"]
  • 相当于:df.get("condition").set("wencha")
  • 第一步的get发出了报警,链式操做其实是两个步骤,先getset
  • get得到的dataframe可能是view(子df),也可能是copy(新的df)pandas发出警告。
  • 核心要诀:pandas的dataframe的修改写操做,只允许在源dataframe上进行
4.解决方法
  • 1.将get+set的两步操做,变成set的一步操做
    df.loc[condition, 'wen_cha'] = df["bWendu"] - df["yWendu"]
    df[condition].head()
    
    在这里插入图片描述
  • 2.使用copy复制dataframe
    df_month3 = df[condition].copy()
    df_month3[condition]["wencha"] = df["bWendu"] - df["yWendu"]
    df_month3.head()
    
    在这里插入图片描述
5.提示
  • Pandas不允许先筛选子dataframe,再进行修改写入
  • 要么使用.loc实现一个步骤直接修改源dataframe
  • 要么先复制一个新的dataframe,再在该对象上进行修改写入

9.Pandas数据排序

1.对Series排序
1.函数及参数说明
Series.sort_values(ascending=True, inplace=False)
  • ascending:默认为True升序排序,False为降序排序
  • inplace:修改原始数据还是复制一份新的数据
2.对高温列进行排序
df["bWendu"].sort_values()
2.对DataFrame排序
1.函数及参数说明
DataFrame.sort_values(by, ascending=True, inplace=False)
  • bystrList<str>,单列排序或者多列排序
  • ascending:默认为True升序排序,False为降序排序
  • inplace:修改原始数据还是复制一份新的数据
2.单列排序
df.sort_values(by='aqi')
3.多列排序
df.sort_values(by=['bWendu', 'yWendu'], ascending=[True, False])

10.Pandas字符串处理

1.使用方法
  • 先获取Series,再在str属性上调用函数
    • 只能在字符串列上使用
    • DataFrame上没有str属性和处理方法
    • Series.str并不是python中的原生字符串,而是一套自己的方法,不过大部分和原生str很像
2.官方地址
3.实例演示
  • object列都是字符串列,可以直接使用str的方法
    在这里插入图片描述
    在这里插入图片描述

  • 1.获取Seriesstr属性

df["bWendu"].str
  • 2.字符串替换函数
df["bWendu"].str.replace("°C""")
  • 3.判断是不是数字
df["bWendu"].str.isnumeric()
  • 4.获取字符串长度
df["bWendu"].str.len()
  • 5.判断字符串是否以什么开头
condition = df["ymd"].str.startswith("2018-03")
df[condition].head()

在这里插入图片描述

  • 6.链式多次处理
df["ymd"].str.replace("-", "").str.slice(0, 6)
# df["ymd"].str.replace("-", "").str[0:6]
  • 7.正则表达式
# 1.新增一列中文日期
def get_nianyueri(x):
	year,month,day = x["ymd"].split("-)
	return f"{year}{month}{day}日"
df["中文日期"] = df.apply(get_nianyueri, axis=1)

# 2.去掉中文日期这一列中的年月日中文字样
# 方法一:
df["中文日期"].str.replace("年", "").str.replace("月", "").str.replace("日", "")
# 方法二:
df["中文日期"].str.replace("[年月日]", "")

11.Pandas的axis参数

1.详解
  • axis=0 或者 “index”
    • 如果是单行操做,就值的是某一行
    • 如果是聚合操作,指的是跨行,想象一下从上往下挤压
  • axis=1 或者 ”columns“
    • 如果是单列操做,就指的是某一列
    • 如果是聚合操做,指的是跨列,想象一下从左往右挤压
2.示例
1.构造数据
import pandas as pd
import numpy as np

df = pd.DataFrame(
    np.arange(12).reshape(3,4),
    columns=["A", "B", "C", "D"]
)

'''
	A	B	C	D
0	0	1	2	3
1	4	5	6	7
2	8	9	10	11
'''
2.单列drop,就是删除某一列
df.drop("A", axis=1)

'''
	B	C	D
0	1	2	3
1	5	6	7
2	9	10	11
'''
3.单行drop,就是删除某一列
df.drop(1, axis=0)

'''
	A	B	C	D
0	0	1	2	3
2	8	9	10	11
'''
4.跨行求取平均值
df.mean(axis=0)

'''
A    4.0
B    5.0
C    6.0
D    7.0
dtype: float64
'''
5.跨列求取平均值
df.mean(axis=1)

'''
0    1.5
1    5.5
2    9.5
dtype: float64
'''
6.增加一列sum_value,保存每行的和
def get_sum_value(x):
	return x["A"] + x["B"] + x["C"] + x["D"]

df["sum_value"] = df.apply(get_sum_value, axis=1)

'''
	A	B	C	D	sum_value
0	0	1	2	3	6
1	4	5	6	7	22
2	8	9	10	11	38
'''

12.Pandas的索引index

1.用途
  • 1.更方便的数据查询
  • 2.使用index可以获得性能提升
  • 3.自动的数据对齐功能
  • 4.更多更强大的数据结构支持
2.示例
1.使用index查询数据
  • 1.读取数据

    import pandas as pd
    
    fpath = './data/ratings.csv'
    df = pd.read_csv(fpath)
    

    在这里插入图片描述

  • 2.设置索引

    df.set_index("userId", inplace=True, drop=False)
    

    在这里插入图片描述

  • 3.使用索引查询

    # 使用index查询
    df.loc[500].head()
    
    # 相当于
    df.loc["userId" == 500].head()
    

    在这里插入图片描述

2.使用index提升性能
  • 如果index是唯一的,Pandas会使用哈希表优化,查询性能O(1)
  • 如果index不是唯一,但是有序,``Pandas会使用二分查找算法,查询性能O(logN)
  • 如果index是完全随机的,那么每次查询都要扫描全表,查询性能为O(N)
  • 实验一:完全随机的顺序查询
    from sklearn.utils import shuffle
    
    df_shuffle = shuffle(df)
    # 检查索引是否是递增的
    df_shuffle.index.is_monotonic_increasing  # False
    # 检查索引是否唯一
    df_shuffle.index.is_unique  # False
    # 计时,查询 id=500的数据性能
    %timeit df_shuffle.loc[500]  # 498 µs ± 28.3 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
    
  • 实验二:将index排序后的查询
    df_sorted = df_shuffle.sort_index()
    # 检查索引是否是递增的
    df_sorted .index.is_monotonic_increasing  # True
    # 检查索引是否唯一
    df_sorted .index.is_unique  # False
    # 计时,查询 id=500的数据性能
    %timeit df_sorted.loc[500]  # 231 µs ± 13.7 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
    
3.使用index能自动对齐数据
  • 包括series和dataframe
    import pandas as pd
    
    s1 = pd.Series([1, 2, 3], index=list("abc"))
    
    '''
    a    1
    b    2
    c    3
    dtype: int64
    '''
    
    s1 = pd.Series([2, 3, 4], index=list("bcd"))
    
    '''
    b    2
    c    3
    d    4
    dtype: int64
    '''
    
    s1 + s2
    
    '''
    a    NaN
    b    4.0
    c    6.0
    d    NaN
    dtype: float64
    '''
    
4.使用index更多更强大的数据结构支持
  • CategoricalIndex,基于分类数据的Index,提升性能
  • MultiIndex,多维索引,用于groupby多维聚合后结果等
  • DatetimeIndex,时间类型索引,强大的日期和时间的方法支持

13.Pandas的Merge语法

1.说明

  • Pandas的Merge,相当于Sq的Join,将不同的表按key关联到一个表

2.用法

pd.merge(left, right, how="Inner", on=None, left_on=None, right_on=None, left_index=False, right_index=False, sort=True, suffixes=('_x', '_y'), copy=True, indicator=False, )
  • left:要merge的dataframe或series
  • right:要merge的dataframe或series
  • how:join类型,‘left’,‘right’,‘outer’,‘inner’
  • on:join的key,left和right都要有这个key
  • left_on:left的df或series的key
  • right_on:right的df或series的key
  • left_index:使用index而不是普通的column做join
  • right_index:使用index而不是普通的column做join
  • sort:排序
  • suffixes:合并表时重名字段自定义命名
  • copy
  • indicator

3.电影数据集join实例

1.电影评分数据集
  • 1.用户对电影的评分数据:ratings.dat

    import pandas as pd
    
    df_ratings = pd.read_csv(
        "./data/ratings.dat",
        sep="::",  # 分隔符为两个字符时会被识别为正则表达式,指定engine=python来告诉pandas他是一个字符串
        engine="python",
        names=["UserID", "MovieID", "Rating", "Timestamp"]
    )
    

    在这里插入图片描述

  • 2.用户本身的信息数据:users.dat

    df_users = pd.read_csv(
        "./data/users.dat",
        sep="::",  # 
        engine="python",
        names="UserID::Gender::Age::Occupation::Zip-code".split("::")
    )
    

    在这里插入图片描述

  • 3.电影本身的数据:movies.dat

    df_momvies = pd.read_csv(
        "./data/movies.dat",
        sep="::",  # 
        engine="python",
        names="MovieID::Title::Geners".split("::")
    )
    

    在这里插入图片描述

  • 4.用户和评分join

    df_ratings_users = pd.merge(
        df_ratings, df_users, left_on="UserID", right_on="UserID", how="inner"
    )
    

    在这里插入图片描述

  • 5.用户和评分join的结果再和电影join

    df_ratings_movies = pd.merge(
        df_ratings, df_momvies, left_on="MovieID", right_on="MovieID", how="inner"
    )
    

    在这里插入图片描述

2.理解merge时数量的对齐关系
1.关系理解
  • one-to-one:关联的key都是唯一的
  • one-to-many:左边key唯一,右边key不唯一
  • many-to-many:左边右边key都不是唯一的
2.一对一关系的merge
  • 1.数据表如下
    在这里插入图片描述

  • 2.合并

    left = pd.DataFrame({
        "sno": [11, 12, 13, 14],
        "name": ["name_a", "name_b", "name_c", "name_d"]
    })
    
    right = pd.DataFrame({
        "sno": [11, 12, 13, 14],
        "age": ["21", "22", "23", "24"]
    })
    
    pd.merge(left, right, on="sno")
    

    在这里插入图片描述

2.一对多关系的merge
  • 1.数据表如下
    在这里插入图片描述
  • 2.合并
    left = pd.DataFrame({
        "sno": [11, 12, 13, 14],
        "name": ["name_a", "name_b", "name_c", "name_d"]
    })
    
    right = pd.DataFrame({
        "sno": [11, 11, 11, 12, 12, 13],
        "grade": ["语文88", "数学90", "英语75", "语文66", "数学55", "英语29"]
    })
    
    pd.merge(left, right, on="sno")
    
    在这里插入图片描述
2.多对多关系的merge
  • 1.数据表如下
    在这里插入图片描述
  • 2.合并
    left = pd.DataFrame({
        "sno": [11, 11, 12, 12, 12],
        "爱好": ["篮球", "羽毛球", "乒乓球", "篮球", "足球"]
    })
    
    right = pd.DataFrame({
        "sno": [11, 11, 11, 12, 12, 13],
        "grade": ["语文88", "数学90", "英语75", "语文66", "数学55", "英语29"]
    })
    
    pd.merge(left, right, on="sno")
    
    在这里插入图片描述
3.理解left joinright joininner joinouter join时数量的对齐关系
1.图示

在这里插入图片描述

2.实例
  • 1.数据如下
    在这里插入图片描述在这里插入图片描述

    left = pd.DataFrame({
        "key": ["K0", "K1", "K2", "K3"],
        "A": ["A0", "A1", "A2", "A3"],
        "B": ["B0", "B1", "B2", "B3"]
    })
    
    right = pd.DataFrame({
        "key": ["K0", "K1", "K4", "K5"],
        "C": ["C0", "C1", "C2", "C3"],
        "D": ["D0", "D1", "D2", "D3"]
    })
    
  • 2.inner join,默认,左右都有的key,才会出现在结果里

    pd.merge(left, right, how='inner')
    

    在这里插入图片描述

  • 3.left join,左边的都会出现在结果里,右边匹配不到的以Null填充

    pd.merge(left, right, how='left')
    

    在这里插入图片描述

  • 4.right join,右边的都会出现在结果里,左边匹配不到的以Null填充

    pd.merge(left, right, how='right')
    

    在这里插入图片描述

  • 5.outer join,左边右边的都会出现在结果里,相互匹配不到的以Null填充

    pd.merge(left, right, how='outer')
    

    在这里插入图片描述

4.重复key
  • 1.图示
    在这里插入图片描述 在这里插入图片描述

  • 2.使用suffixes默认值

    pd.merge(left, right, on="key")
    

    在这里插入图片描述

  • 3.自定义重名的key

    pd.merge(left, right, on="key", suffixes=("_left", "_right"))
    

    在这里插入图片描述

14.Pandas的Concat合并

1.语法
1.说明
  • 使用某种合并方式(inner/outer)
  • 沿着某个轴向(axis=0/1)
  • 把多个Pandas对象(DataFrame/Series)合并成一个
2.concat语法
pd.concat(objs, axis=0, join="outer", ignore_index=False)
  • objs:一个列表,内容可以是DataFrame或者Series,可以混合
  • axis:默认是0,代表按行合并,如果等于1代表按列合并
  • join:合并的时候索引的对齐方式,默认是outer join,也可以是inner join
  • ignore_index:是否忽略掉原来的数据索引
3.append语法
df.append(other, ignore_index=False)
  • append只有按行合并,并没有按列合并,相当于concat按行合并的简写
  • other:单个dfseriesdict或者列表
  • ignore_index:是否忽略掉原来的数据索引
2.使用场景
  • 批量合并想同格式的Excel
  • DataFrame添加行
  • DataFrame添加列
3.使用pandas.concat合并数据
1.数据准备
df1 = pd.DataFrame({
    "A": ["A0", "A1", "A2", "A3"],
    "B": ["B0", "B1", "B2", "B3"],
    "C": ["C0", "C1", "C2", "C3"],
    "D": ["D0", "D1", "D2", "D3"],
    "E": ["E0", "E1", "E2", "E3"]
})

df2 = pd.DataFrame({
    "A": ["A4", "A5", "A6", "A7"],
    "B": ["B4", "B5", "B6", "B7"],
    "C": ["C4", "C5", "C6", "C7"],
    "D": ["D4", "D5", "D6", "D7"],
    "F": ["F4", "F5", "F6", "F7"]
})

在这里插入图片描述在这里插入图片描述

2.默认concat,参数为axis=0、join=outer、ignore_index=False
pd.concat([df1, df2])

在这里插入图片描述

3.使用ignore_index=True忽略原来的索引
pd.concat([df1, df2], ignore_index=True)

在这里插入图片描述

4.使用join=inner过滤掉不匹配的列
pd.concat([df1, df2], ignore_index=True, join="inner")

在这里插入图片描述

5.使用axis=1进行列合并
pd.concat([df1, df2], axis=1)

在这里插入图片描述

6.DdataFrame和Series混合关联
  • 增加一列
s1 = pd.Series(list(range(4)), name='F')
pd.concat([df1, s1], axis=1)

在这里插入图片描述

  • 增加一行
# 添加行
s2 = pd.Series({i: i+str(4) for i in "ABCDE"}, name=4)
df1.append(s2)

在这里插入图片描述

4.使用DataFrame.append按行合并数据
1.数据准备

在这里插入图片描述在这里插入图片描述

df1 = pd.DataFrame(
    [
        [1, 2],
        [3, 4]
    ],
    columns=list("AB")
)

df2 = pd.DataFrame(
    [
        [5, 6],
        [7, 8]
    ],
    columns=list("AB")
)
2.给df1添加一个名为df2的dataframe
df1.append(df2)

在这里插入图片描述

3.忽略原索引
df1.append(df2, ignore_index=True)

在这里插入图片描述

4.可以一行一行的给DataFrame添加数据
  • 低性能版本
df = pd.DataFrame(
    columns=["A"]
)

在这里插入图片描述

for i in range(5):
    df = df.append({"A": i}, ignore_index=True)
df

在这里插入图片描述

  • 高性能版本
pd.concat(
	# 数据量过大时,需要分批
    [pd.DataFrame([i], columns=["A"]) for i in range(5)],
    ignore_index=True
)

在这里插入图片描述

15.Pandas批量拆分与合并Excel文件

1.实例演示
1.将一个大的Excel等份拆成多个小的Excel
  • 1.数据读取
import pandas as pd

df_source = pd.read_excel('./data/crazyant_blog_articles.xlsx')
df_source.head()
df_source.shape  # (258, 3)

在这里插入图片描述

  • 2.计算拆分后的每个excel的行数
# 拆分列表
user_names = ['zs', 'ls', 'ww', 'zl', 'sq', 'qb']
# 获取总行数
total = df_source.shape[0]

# 计算每个人的任务条目
split_size = total // len(user_names)
if split_size % len(user_names) != 0:
    split_size += 1
  • 3.拆分成多个dataframe
df_subs = []
for idx, user_name in enumerate(user_names):
    # iloc的开始索引
    begin = idx * split_size
    # iloc的结束索引
    end = begin + split_size
    # 实现df按照iloc拆分
    df_sub = df_source.iloc[begin:end]
    # 将每个子df存入列表
    df_subs.append((idx, user_name, df_sub))
  • 4.将每个dataframe存入excel
for idx, user_name, df_sub in df_subs:
    file_name = f"./split_dir/{idx}_{user_name}.xlsx"
    df_sub.to_excel(file_name, index=False)
2.将多个小的Excel合并成一个大的Excel,并且标记来源
  • 1.遍历文件夹,得到要合并的Excel名称列表
import os

excel_names = []
for excel_name in os.listdir('./split_dir'):
    excel_names.append(excel_name)
  • 2.分别读取到dataframe
df_list = []

for index, excel_name in enumerate(excel_names):
    # 读取每个excel到df
    excel_path = f"./split_dir/{excel_name}"
    df_split = pd.read_excel(excel_path)
    # 得到username
    username = excel_name.replace(f"{index}_", "").split(".")[0]
    # 每个df添加1列,用户名
    df_split["username"] = username
    print(df_split)
    df_list.append(df_split)
  • 3.使用pd.concat进行合并
df_merge = pd.concat(df_list)
df_merge.shape  # (258, 4)
df_merge.head()
df_mergr["username"].value_counts()

在这里插入图片描述
在这里插入图片描述

  • 4.将合并后的dataframe输出到excel中
# index=False:忽略每个表中自己的索引
df_merge.to_excel(f"./split_dir/new_articles.xlsx", index=False)

16.Pandas实现group by分组

1.分组使用聚合函数做数据统计
1.准备数据
import pandas as pd
import numpy as np

%matplotlib inline  # 加这一句,能在jupyter notebook展示matplot图表

df = pd.DataFrame({
	"A": ['foo', 'bar', 'foo', 'bar', 'foo', 'bar', 'foo', 'foo'],
	"B": ['one', 'one', 'two', 'three', 'two', 'two', 'one', 'three'],
	"C": np.random.randn(8),
	"D": np.random.randn(8),
})

在这里插入图片描述

2.单个group by查询所有数据列的统计
df.groupby('A').sum()

在这里插入图片描述

  • 1.groupby中的A变成了数据的索引列
  • 2.因为要统计sum,但B列不是数字,所以被自动忽略掉
  • 3.按照A列分组,分为两组foobar,然后计算foobarCD列对应的值加和后的结果
2.多个列groupby,查询所有数据列的统计
df.groupby(['A', 'B']).mean()

在这里插入图片描述

  • ('A', 'B')成对变成了二级索引
df.groupby(['A', 'B'], as_index=False).mean()

在这里插入图片描述

3.同时查看多种数据统计
df.groupby('A').agg([np.sum, np.mean, np.std])

在这里插入图片描述

4.查看单列的结果数据统计
df.groupby('A')['C'].agg([np.sum, np.mean, np.std])
# df.groupby('A').agg([np.sum, np.mean, np.std])['C']

在这里插入图片描述

5.不同列使用不同的聚合函数
df.groupby('A').agg({"C": np.sum, "D":np.mean})

在这里插入图片描述

df.groupby('A').agg({'C':[np.mean,'sum'],'D':['count',np.std]})

在这里插入图片描述

2.遍历groupby的结果理解执行流程
1.遍历单个列聚合的分组
g = df.groupby("A")
for name, group in g:
    print(name)
    print(group)

在这里插入图片描述

  • 获取单个分组的数据
g.get_group("bar")

在这里插入图片描述

2.遍历多个列聚合的分组
g = df.groupby(["A", "B"])
for name, group in g:
    print(name)
    print(group)

在这里插入图片描述

  • 获取单个分组的数据
g.get_group(('foo', 'two'))

在这里插入图片描述

  • 查看groupby后的C列,生成一个Series
for name, group in g['C']:
    print(name)
    print(group)
    print(type(group))

在这里插入图片描述

3.实例分组探索天气数据
1.准备数据
import pandas as pd

fpath = "./data/beijing_tianqi_2018.csv"
df = pd.read_csv(fpath)
# 替换温度后面的 °C
df.loc[:, "bWendu"] = df["bWendu"].str.repace("°C", "").astype("int32")
df.loc[:, "yWendu"] = df["yWendu"].str.repace("°C", "").astype("int32")
df.head()

在这里插入图片描述

2.查看每个月的最高温度
  • 新增一列月份
df["month"] = df["ymd"].str[:7]
df.head()

在这里插入图片描述

  • 按照月份分组统计
data = df.groupby("month")["bWendu"].max()

在这里插入图片描述

type(data)  # pandas.core.series.Series
data.plot()

在这里插入图片描述

2.查看每个月的最高温度、最低温度、平均空气质量指数
group_data = df.groupby("month").agg({"bWendu": np.max, "yWendu": np.min, "aqi": np.mean})

在这里插入图片描述

group_data.plot()

在这里插入图片描述

17.Pandas的分层索引MultiIndex

1.分层索引作用
  • 1.分层索引:在一个轴上向上拥有多个索引层级,可以表达更高维度的数据形式
  • 2.可以方便的进行数据筛选,如果有序则性能更好
  • 3.groupby等操作的结果,如果是多KEY,结果是封层索引
  • 4.一般不需要自己创建分层索引(MultiIndex有构造函数,但一般不用)
2.实例演示
1.数据展示
  • 以下为:百度、阿里巴巴、爱奇艺、京东四家公司的10天股票数据
    在这里插入图片描述
2.Series的分层索引MultiIndex
  • 1.数据准备
import pandas as pd

%matplotlib inline

stocks = pd.read_excel('./data/internet.xlsx')
stocks.shape  # (12, 8)
stocks.head(3)

在这里插入图片描述

stocks['公司'].unique()
# array(["BIDU", "BABA", "IQ", "JD"], dtype=object)
stocks.index
# RangeIndex(start=0, stop=12, setp=1)
stocks.groupby("公司")["收盘"].mean()

在这里插入图片描述

  • 2.分层索引MultiIndex
ser = stocks.groupby(['公司', '日期'])["收盘"].mean()

在这里插入图片描述

ser.index

在这里插入图片描述

# 把二级索引变成列
ser.unstack()

在这里插入图片描述

ser.reset_index()

在这里插入图片描述

3.Series有多层索引怎样刷选数据
  • 1.指定个索引晒筛选
ser = stocks.groupby(['公司', '日期'])["收盘"].mean()

在这里插入图片描述

ser.loc["BIDU"]

在这里插入图片描述

  • 2.多层索引使用元组形式筛选
# 
ser.loc[("BIDU", "2019-10-02")]

在这里插入图片描述

  • 3.多层索引使用切片形式筛选
# 
ser.loc[:, "2019-10-02"]

在这里插入图片描述

4.DataFrame的多层索引MultiIndex
  • 1.数据准备
stocks.head()

在这里插入图片描述

  • 2.设置分层索引
stocks..set_index(["公司", "日期"], inplace=True)

在这里插入图片描述

  • 3.查看分层索引
stocks.index

在这里插入图片描述

  • 4.对分层索引进行排序
stocks.sort_index(inplace=True)

在这里插入图片描述

5.DataFrame有多层索引怎样刷选数据
  • 【重要知识】在选择数据时
    • 元组(key1, key2)代表筛选多层索引,其中key1是索引的第一级,key2是索引的第二级,比如:key1=JD, key2=2019-10-02
    • 列表 [key1, key2] 代表同一层级的多个KEY,其中key1key2是并列的同级索引,比如:key1=JD, key2=BABA
stocks.loc["BIDU"]

在这里插入图片描述

stocks.loc[("BIDU", "2019-10-02"), :]

在这里插入图片描述

stocks.loc[("BIDU", "2019-10-02"), "开盘"]

在这里插入图片描述

stocks.loc[["BIDU", "JD"], :]

在这里插入图片描述

stocks.loc[(["BIDU", "JD"], "2019-10-03"), :]

在这里插入图片描述

stocks.loc[(["BIDU", "JD"], "2019-10-03"), "收盘"]

在这里插入图片描述

stocks.loc[("BIDU", ["2019-10-02", "2019-10-03"]), "收盘"]

在这里插入图片描述

# slice(None)代表筛选这一索引所有的内容
stocks.loc[(slice(None), ["2019-10-02", "2019-10-03"]), "收盘"]

在这里插入图片描述

stocks.reset_index()

在这里插入图片描述

18.Pandas的数据转换函数map、apply、applymap

1.数据转换函数对比
  • 1.map:只用于Series,实现每个值—>值的映射
  • 2.apply:用于Series实现每个值的处理,用于DataFrame实现某个轴的Series的处理
  • 3.applymap:只能用于DataFrame,用于处理该DataFrame的每个元素
2.map用于Series值的转换
1.将股票代码英文转换成中文名字
import pandas as pd

stocks = pd.read_excel("./data/internet.xlsx")
stocks.head()

在这里插入图片描述

stocks["公司"].unique()

在这里插入图片描述

2.使用Series.map(dict)进行转换
  • function的参数是Series的每个元素的值
dict_company_names = {
	"bidu": "百度",
	"baba": "阿里巴巴",
	"iq": "爱奇艺",
	"jd": "京东"
}
stocks["中文公司1"] = stocks["公司"].str.lower().map(dict_company_names)
stocks.head()

在这里插入图片描述

3.使用Series.map(function)进行转换
stocks["中文公司2"] = stocks["公司"].map(lambda x: dict_company_names[x.lower()])
stocks.head()

在这里插入图片描述

3.apply用于Series和DataFrame的转换
1.Series.apply(function),函数的参数是每个值
stocks["中文公司3"] = stocks["公司"].apply(lambda x: dict_company_names[x.lower()])
stocks.head()

在这里插入图片描述

2.DataFrame.apply(function),函数的参数是Series
stocks["中文公司3"] = stocks.apply(lambda x: dict_company_names[x["公司"].lower()], axis=1)
stocks.head()

在这里插入图片描述

  • 1.apply是在stocks这个DataFrame上进行调用;
  • 2.lambda x,x是一个Series,因为指定了axis=1,所以Series的key是由列名组成,可以使用x["公司"]获取公司这一列数据,然后进行处理
4.applymap用于DataFrame所有值的转换
sub_df = stocks[["收盘", "开盘", "高", "低", "交易量"]]
sub_df.head()

在这里插入图片描述

  • 将上述数值取整
sub_df.applymap(lambda x: int(x))
sub_df

在这里插入图片描述

  • 方法二:
stocks.loc[:, ["收盘", "开盘", "高", "低", "交易量"]] = sub_df.applymap(lambda x: int(x))
stocks.head()

在这里插入图片描述

19.Pandas对groupby后的数据应用apply

1.图解说明

在这里插入图片描述

2.GroupBy(function)
  • function的第一个参数是dataframe
  • function的返回结果,可以是dataframe、series、单个值,甚至和输入DataFrame完全没有关系
3.实例演示
1.怎样对数值列按分组的归一化
  • 1.归一化:将不同范围的数值进行归一化,映射到【0-1】区间
    • 更容易做到数据的横向对比,比如价格字段是几百到几千,增幅字段是0到100
    • 机器学习模型学的更快,性能更好
      在这里插入图片描述
  • 2.用户对电影评分的归一化
import pandas as pd

ratings = pd.read_csv(
    "./data/ratings.dat",
    sep="::",
    engine="python",
    names="UserID::MovieID::Rating::Timestamp".split("::")
)
ratings.head()

在这里插入图片描述

  • 实现按照用户ID分组,然后对其中一列归一化
def ratings_norm(df):
    min_value = df["Rating"].min()
    max_value = df["Rating"].max()
    df["Rating_norm"] = df["Rating"].apply(lambda x: (x - min_value) / (max_value - min_value))
    return df
ratings = ratings.groupby("UserID").apply(ratings_norm)

在这里插入图片描述

ratings[ratings["UserID"] == 1].head()

在这里插入图片描述

2.怎样获取每个分组的TOPN数据
fpath = "./data/beijing_tianqi_2018.csv"
df = pd.read_csv(fpath)
# 替换温度后面的 °C
df.loc[:, "bWendu"] = df["bWendu"].str.repace("°C", "").astype("int32")
df.loc[:, "yWendu"] = df["yWendu"].str.repace("°C", "").astype("int32")
# 增加一列月份
df["month"] = df["ymd"].str[:7]
df.head()

在这里插入图片描述

def getWenduTopN(df, topn):
    """
    df: 每个月份分组group的df
    """
    # df.sort_values(by="bWendu"):按高温一列升序排序
    # [["ymd", "bWendu"]]:取年月日和高温两列数据
    # [-topn:]:因为是升序,所以取-topn
    return df.sort_values(by="bWendu")[["ymd", "bWendu"]][-topn:]

df.groupby("month").apply(getWenduTopN, topn=2).head()

在这里插入图片描述

20.Pandas使用stack和pivot实现数据透视

1.作用
  • 将列式数据变成二维交叉形式,便于分析,叫做重塑或透视
    在这里插入图片描述
2.流程
  • 1.经过统计得到多维度指标数据
  • 2.使用unstack实现数据二维透视
  • 3.使用pivot简化透视
  • 4.stack、unstack、pivot的语法
3.经过统计得到多维度指标数据
1.实例:统计得到电影评分数据集,每个月份的每个分数被评分多少次(月份、分数1-5、次数)
  • 1.读取数据
import pandas as pd
import numpy as np

%matplotlib inline

df = pd.read_csv(
    "./data/ratings.dat",
    header=None,
    sep="::",
    engine="python",
    names="UserID::MovieID::Rating::Timestamp".split("::")
)
df.head()

在这里插入图片描述

  • 2.增加一列时间日期
# 增加一列时间日期,由秒格式的Timestamp字段转换而来
df["pdate"] = pd.to_datetime(df["Timestamp"], unit="s")
df.head()

在这里插入图片描述

  • 3.查看各个字段类型
df.dtypes

在这里插入图片描述

  • 4.实现数据统计
  • 1.统计
# 按照月份和评分分组,创建两个索引,取Rating这个series,统计后倒序排列(方便验证结果)
df_group = df.groupby([df["pdate"].dt.month, "Rating"])["Rating"].agg({"pv": np.size}).sort_values("pdate", ascending=False)

在这里插入图片描述

  • 2.验证12月份5分的评价有多少条
    • 1.新增一列月份
      df["month"] = df["pdate"].dt.month
      
    • 2.过滤12月份评分为5分的数据,按照评分统计条数
      df[(df["Rating"] == 5) & (df["month"]==12)]["Rating"].value_counts()
      
    • 3.得到结果为:5 26760 Name: Rating, dtype: int64
2.使用unstack实现数据二维透视
  • 1.使用unstack实现透视
df_stack = df_group.unstack()

在这里插入图片描述

df_stack.plot()

在这里插入图片描述

  • 2.使用stack还原
df_stack.stack().head()

在这里插入图片描述

3.使用pivot简化透视
df_group.head(20)

在这里插入图片描述

df_reset = df_group.reset_index()
df_reset.head()

在这里插入图片描述

df_pivot = df_reset.pivot("pdate", "Rating", "pv")
df_pivot.head()

在这里插入图片描述

df_pivot.plot()

在这里插入图片描述

4.stack、unstack、pivot的语法
  • pivot:方法相当于对df使用set_index创建分层索引,然后使用unstack
  • stackDateFrame.stack(level=-1, dropna=True),将column变成index,类似把横放的书籍变成竖放
    • level:-1代表错层索引的最内层,可以通过0、1、2指定多层索引对应的层

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值