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.isnull
和notnull
:检测是否是空值,可用于DataFrame
和Series
2.dropna
:丢弃、删除缺失值
axis
:删除行还是列,{0 or ‘index’, 1 or columns},default 0how
:如果等于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
发出了报警,链式操做其实是两个步骤,先get
后set
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)
by
:str
或List<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.获取
Series
的str
属性
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或seriesright
:要merge的dataframe或serieshow
:join类型,‘left’,‘right’,‘outer’,‘inner’on
:join的key,left和right都要有这个keyleft_on
:left的df或series的keyright_on
:right的df或series的keyleft_index
:使用index而不是普通的column做joinright_index
:使用index而不是普通的column做joinsort
:排序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 join
、right join
、inner join
、outer 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
:单个df
、series
、dict
或者列表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列分组,分为两组
foo
和bar
,然后计算foo
和bar
在C
和D
列对应的值加和后的结果
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,其中
key1
和key2
是并列的同级索引,比如:key1=JD, key2=BABA
- 元组(key1, key2)代表筛选多层索引,其中
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
- 1.新增一列月份
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
stack
:DateFrame.stack(level=-1, dropna=True)
,将column
变成index
,类似把横放的书籍变成竖放level
:-1代表错层索引的最内层,可以通过0、1、2指定多层索引对应的层