pandas
Series
Series这种数据结构类似python中的列表,Series = 列表(value) + 标签(index),是一个一维的数据结构
通过列表构造Series
s1 = pd.Series(["a", "b", "c", "d", "e"])
通过字典构造Series
s2 = pd.Series({"name":"Tom", "age":15, "location":"China"})
通过切片获取特定的值
s2.values[1:3]
获取s2的index值和value值
s2.index
s2.values
修改index值
s1.index = ["one", "two", "three", "four", "five"]
修改values值
s1[:] = ["A", "B", "C", "D", "E"]
通过位置索引获取并修改值
s1[2] = "C"
通过index标签获取并修改值
s1["two"] = "B1"
s1[["one", "two"]] = ["Billy", "Apple"]
DataFrame
DataFrame是一个具有行、行标签以及列、列标签的二维数据结构,类似于一个表格数据
通过列表创建DataFrame
df = pd.DataFrame(["a", "b", "c"])
通过字典创建DataFrame
df = pd.DataFrame({"小写":["a", "b", "c"], "大写":["A", "B", "C"]})
指定行标签和列标签
df = pd.DataFrame([["one", "a"], ["two", "b"], ["three", "c"]], index=["一", "二", "三"], columns=["1列", "2列"])
修改某行或某列的标签,必须使用rename
df.rename(index={"line2":"行2"}, inplace=True)
df.rename(columns={"col1":"列1"}, inplace=True)
DataFrame基本属性
查询df的形状
df.shape
获取df的行标签
df.index
获取df的列标签
df.columns
获取df的值
df.values
进行行列转换
df.T
获取df中指定列的值
df["列名"]
统计df中指定列的数据个数,空值不计算在内
df["列名"].value_counts()
看指定列有哪些唯一值
df["列名"].unique()
统计指定列有多少个唯一值
df["列名"].nunique()
返回df中每列的唯一值的个数
df.nunique()
描述df中的基本情况,针对数值型的列有效
df.describe()
查看df中每列数据类型等信息
df.info()
查看df中前5行的值
df.head()
查看df中后5行的值
df.tail()
从excel文件中读取数据
df = pd.read_excel(r"文件路径", sheet_name="Sheet1", header=None, names=["列1", "列2"],nrows=len(df), skiprows=[0])
切换当前工作路径
import os
os.chdir(r"文件路径")
读取指定列
df = pd.read_excel(r"xxx.xlsx", usecols=["列1", "列2"])
df = pd.read_excel(r"xxx.xlsx", usecols=[1, 2, 3])
指定列名为index
df.pd.read_excel(r"xxx.xlsx", index_col="列名")
读取csv文件,引擎设置为python才能兼容utf8
df = pd.read_csv(r"xxx.csv", engine="python", index_col=0, sep="#")
从文本文件中读取
pd.read_table(r"xxx.txt", engine="python", sep="@")
数据预处理(数据清洗)通常包括
1.缺失值(空值)处理;2.重复值处理;3.异常值处理;4.数据类型转换;5.索引设置
查找缺失值思路,先看数据集中各列有没有缺失值,再看缺失值所占的比例,比例小可直接删除
查看每列数据的缺失值总数
df.isnull().sum()
查看每列空值所占比例,5%以下可以考虑删除
df.apply(lambda x: sum(x.isnull()) / len(x), axis=0)
删除带有缺失值的整行数据,一旦有缺失值就直接删除
df.dropna(axis=0, how="any", inplace=False)
读取时替换默认的缺失值
df = pd.read_excel(r"xxx.xlsx", na_values=["暂无", "未知"])
读取后在df中使用replace方法进行替换
df.replace("暂无", np.nan, inplace=True)
如果售价中出现"万",该如何替换
df["售价"].apply(lambda x: str(x).replace("万", "") if x is not np.nan else x).astype(np.float)
用平均值填充缺失值
df.fillna({"售价": df["售价"].mean()})
删除重复值
df.drop_duplicates(subset=["列名1", "列名2"], keep="first")
重置索引
df.reset_index(drop=True)
异常值操作
异常值特征:异常值并不是错误值,是偏离正常范围的值。异常值出现频率较低,但会对实际分析造成误差
异常值检测:
1.根据业务经验划定不同指标的正常范围,超过范围的值算异常值
2.如果数据服从正态分布,可以用3sigma原则:一个数与平均值之间的偏差超过3倍标准差,则认定为异常值
3.不符合正态分布的数据,一般通过绘制箱型图,把大于(小于)箱型图上边缘(下边缘)的点称为异常值
判断异常点的临界值
# 正的2倍标准差的点
except_high = df["weight"].mean() + 2 * df["weight"].std()
# 负的2倍标准差的点
except_low = df["weight"].mean() - 2 * df["weight"].std()
极端异常点的临界值
# 正的3倍标准差的点
extrme_except_high = df["weight"].mean() + 3 * df["weight"].std()
# 负的3倍标准差的点
extrme_except_low = df["weight"].mean() - 3 * df["weight"].std()
寻找异常值
df[(df["weight"] > except_high) | (df["weight"] < except_low)]
求1/4分位数
Q1 = df["count"].quantile(q=0.25)
求3/4分位数
Q3 = df["count"].quantile(q=0.75)
下界
low = Q1 - 1.5 * (Q3 - Q1)
上界
high = Q3 + 1.5 * (Q3 - Q1)
数据类型转换
数值类型转换
df["售价"].astype(np.int32)
日期类型转换
df["日期"] = pd.to_datetime(df["日期"], format="%Y-%m-%d")
df["日期"].dt.year
df["日期"].dt.day
读取文件时直接转换日期值
df = pd.read_excel(r"xxx.xlsx", parse_dates=["要转为日期的列名"])
字符串类型处理
df["部门"].str.replace("部", "组")
df["部门"].str[:2]
索引设置
df.columns = ["日期", "售价", "姓名", "部门"]
df.index = ["a", "b", "c"]
设置特定的列作为行索引
df.set_index("日期")
重置索引(针对层次化索引),将索引列当作普通的columns返回
df.reset_index(level=0, drop=True)
筛选数据
选择单列
df["售价"]
选择多列
df[["售价", "日期"]]
通过列的位置索引选择列
df.iloc[[0, 3, 4], 1:5]
通过位置标签选择
df.loc[["a", "c", "f"], ["售价", "部门"]]
数值排序
df.sort_values(by=["消费金额", "年龄"], ascending=[False, True])
数据删除,默认按照行来删
df.drop(["消费金额", "年龄"], axis=1)
df.drop(df.columns[[3, 4]], axis=1)
df.drop(df.index[1:4])
插入新的行或列(插哪里,列名, 插什么值)
插入列
df.insert(2, "新列", [i for i in range(10)])
插入到最后列
df["再加一列"] = []
map函数用法
for i in map(lambda x: str(x) + "ok", [1, 2, 3])
apply和applymap函数
apply针对某一行或某一列元素执行相同操作(Series对象)
df["消费金额"].apply(lambda x: str(x) + "元")
df.iloc[2].apply(lambda x: str(x) + "ok")
applymap是针对Dataframe中所有数据进行某种操作
df.applymap(lambda x: str(x) + "ok")
数据运算
求众数(出现最多的数)
df["sale2015"].mode()
求方差
df["sale2015"].var()
时间序列
获取日期和时间
from datetime import datetime
获取当前时间
datetime.now()
获取当前年份
datetime.now().year
获取当前月份
datetime.now().month
获取当前星期
datetime.now().weekday() + 1
datetime.now().isocalendar() # 返回值格式(年,周,星期几)
指定时间格式
datetime.now().strftime("%F")
时间序列查询(只有时间序列是行索引时才能操作)
df["2019"]
df["2019-08"]
df["2019-08-01":"2019-08-11"]
df[df["购买日期"] > datetime(2019, 8, 1)]
时间偏移
from datetime import timedelta
构造时间
date = datetime(2020, 3, 20, 20, 50)
时间往后移1天
date + timedelta(days=1)
延后35秒
date + timedelta(seconds=35)
pandas自带的库实现时间偏移
from pandas.tseries.offsets import Day,Hour,Minute
date = datetime(2020, 3, 20, 20, 50)
date + Day(1)
date + Hour(2)
date + Minute(38)
DataFrame拼接,默认竖向拼接,横向拼接则加参数axis=1
pd.concat([df1, df2], ignore_index=True, axis=0)
结果导出pd.to_xxx()
导出为excel文件(首先要安装pip3 install openpyxl)
df.to_excel("导出文件.xlsx", index=False)
设置需要导出的列
df.to_excel("xxx.xlsx", index=False, columns=["列1", "列2"])
注:浮点数要转换为字符串之后,才能进行replace
导出时的缺失值处理(缺失值设为0)
df.to_excel("xxx.xlsx", index=False, na_rep=0)
导出csv文件
df.to_csv("xxx.csv", sep=",", index=False)
数据可视化matplotlib
import matplotlib.pyplot as plt
%matplotlib inline
plt.rcParams["font.sans-serif"] = "SimHei" # 中文显示
plt.rcParams["axes.unicode_minus"] = False # 解决负号无法显示问题
%config InlineBackend.figure_format = "svg" # 显示更清晰
建立和绘制画布和坐标系
创建一个宽为8,高为6的画布
fig = plt.figure(figsize=(8, 6))
在画布上创建坐标系
1.add_subplot()
ax1 = fig.add_subplot(1, 1, 1) # 创建1行1列的坐标系,坐标系序号为1
2.plt.subplot2grid()
plt.subplot2grid((2, 2), (0, 0)) # 生成2行2列坐标系,且在(0, 0)位置
3.plt.subplot()
plt.subplot(2, 2, 1) # 生成2行2列坐标系,坐标系序号为1
4.plt.subplots()
fig, axes = plt.subplots(2, 2)
设置坐标轴的标题
plt.xlabel("xxxx", labelpad=5, fontsize=16, color="r", fontweight="bold")
plt.ylabel("xxxx")
设置坐标轴刻度
plt.xticks(x, [(str(i) + "月") for i in range(1, 7)])
plt.yticks()
设置网格线
plt.grid(axis="x")
设置图例
plt.legend(loc="best")
设置标题
plt.title("xxxx", loc="center")
设置数据标签
plt.text(x坐标的值, y坐标的值, "文字内容")
for a, b in zip(a, b):
plt.text(a, b, b, ha="center", va="bottom", fontsize=8)
柱状图
plt.bar(x, y, width=0.5, align="center", label="xxxx")
条形图
plt.barh(x, height=0.5, width=y, align="center")
直方图,观察数据的分布形态,主要用于连续型变量
ser = pd.Series(data)
ax = ser.plot(kind="hist", bins=20, facecolor="r", edgecolor="black", alpha=0.6)
ser.plot(kind="kde", ax=ax, secondary_y=True) # 核密度图
等距划分
pd.cut(df["列名"], bins=20)
箱型图
plt.boxplot(df["列名"],
patch_artist=True # 是否进行箱体填充
, showmeans=True # 是否显示均值线
, showfliers=True # 是否显示异常值
, boxprops={"color":"b", "facecolor":"yellow"} # 设置箱体属性,如颜色
, flierprops={"marker":"o", "markerfacecolor":"r"} # 设置异常值属性
, labels=[""]) # 让x轴不显示刻度值
散点图,发现变量间的相关关系
plt.scatter(x, y, marker="o", s=50)
蚂蚁学python
pandas读取数据
读取csv
df = pd.read_csv("xxx.csv")
查看前几行
df.head()
查看数据的形状
df.shape
查看列名列表
df.columns
查看索引列
df.index
查看每列的数据类型
df.dtypes
读取txt文件
df = pd.read_csv(fpath, sep="\t", header=None, names=["", "", ""])
读取excel
df = pd.excel("xxx.xlsx")
读取mysql
import pymysql
conn = pymysql.connect(host="", port="", user="", password="", database="", charset="utf8")
df = pd.read_sql("sql语句", con=conn)
DataFrame:二维数据,整个表格,多行多列
Series:一维数据,一行或一列
创建
列表创建Series
pd.Series([])
获取索引
s.index
获取数据
s.values
创建Series时,指定index
pd.Series([], index=[])
字典创建Series,key变索引,value变values
pd.Series({})
字典创建DataFrame,key变列标签,value变values
pd.DataFrame({"xxx":[], "xxx":[], "xxx":[]})
查询
查询一列
df["列名"]
查询多列
df[["列1", "列2"]]
查询一行
df.loc[1]
查询多行(loc包含末尾元素)
df.loc[1:3]
设定索引为日期,方便按日期筛选
df.set_index("ymd", inplace=True)
替换掉温度的后缀℃
df.loc[:, "wendu"] = df["wendu"].str.replace("℃", "").astype("int32")
1.得到单个值
df.loc["2018-01-03", "wendu"]
2.给列传入一个列表,得到一个Series
df.loc["2018-01-03", ["bwendu", "ywendu"]]
给行传入一个列表,得到一个Series
df.loc[["2018-01-03", "2018-01-05"], ["wendu"]]
给行和列传入一个列表,得到一个DataFrame
df.loc[["2018-01-03", "2018-01-05"], ["bwendu", "ywendu"]]
3.行按区间查询
df.loc["2018-01-03":"2018-01-05", "wendu"]
列按区间查询
df.loc["2018-01-03", "bwendu":"fengxiang"]
行和列都按区间查询
df.loc["2018-01-03":"2018-01-05", "bwendu":"fengxiang"]
4.使用条件表达式查询
df.loc[df["wendu"] < 10, :]
5.调用函数查询(这时,把每一行的Series传给df)
df.loc[lambda df: (df["bwendu"]<=30) & (df["ywendu"]>=15), :]
自己写函数,查询9月空气质量好的数据
def query_data(df):
# 对每一行进行处理
return df.index.str.startswith("2018-09") & df["aqiLevel"] == 1
df.loc[query_data, :]
新增数据列
1.直接赋值
df.loc[:, "wencha"] = df["bWendu"] - df["yWendu"]
2.apply方法
def get_wendu_type(x):
if x["bWendu"] > 33:
return "高温"
elif x["yWendu"] < 10:
return "低温"
return "常温"
df.loc[:, "wendu_type"] = df.apply(get_wendu_type, axis=1)
3.assign方法(可以同时新增多个列)
df.assign(
yWendu_huashi = lambda x: x["yWendu"] * 9 / 5 + 32,
bWendu_huashi = lambda x: x["bWendu"] * 9 / 5 + 32
)
4.按条件选择分组分别赋值
df["wencha_type"] = ""
df.loc[df["bWendu"] - df["yWendu"] > 10, "wencha_type"] = "温差大"
df.loc[df["bWendu"] - df["yWendu"] <= 10, "wencha_type"] = "温差正常"
统计函数
描述
df.describe()
查看单个Series
df["bWendu"].mean()
唯一去重
df["tianqi"].unique()
按值计数
df["fengxiang"].value_counts()
协方差
协方差为正,说明x和y同向变化,协方差越大,同向程度越高
协方差为负,说明x和y反向运动,协方差越小,反向程度越高
df.cov()
相关系数
df.corr()
单独看两个变量的相关系数
df["aqi"].corr(df["yWendu"])
缺失值处理(检测、删除、填充)
检测空值
df.isnull()
df["列名"].isnull()
检测不为空值
df["列名"].notnull()
筛选没有空分数的所有行
df.loc[df["score"].notnull(), :]
删除全是空值的列
df.dropna(axis="columns", how="all", inplace=True)
删除全是空值的行
df.dropna(axis="index", how="all", inplace=True)
将分数列为空的值填充为0分
df.fillna({"分数": 0})
df.loc[:, "分数"] = df["分数"].fillna(0)
将姓名的缺失值用前面的有效值填充
df.loc[:, "姓名"] = df["姓名"].fillna(method="ffill")
将清洗好的excel保存
df.to_excel("xxx.xlsx", index=False)
SettingsWithCopyWarning解决方案
原因:在子的dataFrame中设置新列,如:
condition = df["ymd"].str.startswith("2018-03")
df[condition]["wencha"] = df["bWendu"] - df["yWendu"]
链式操作其实是2个步骤,先get后set,get得到的dataFrame可能是view,也可能是copy
pandas的DataFrame修改写操作,只允许在源DataFrame上进行,并且要一步到位
解决方法1:将get和set两步操作,改成set的一步操作
df.loc[condition, "wencha"] = df["bWendu"] - df["yWendu"]
解决方法2:使用copy复制DataFrame
df_month3 = df[condition].copy()
df_month3["wencha"] = df["bWendu"] - df["yWendu"]
总之,pandas不允许先筛选子DataFrame再进行修改写入
排序
Series排序
s.sort_values(ascending=False, inplace=True)
DataFrame排序
df.sort_values(by=["列名"], ascending=True, inplace=True)
字符串处理
1.使用方法:先获取Series的str属性,然后在属性上调用函数
2.只能在字符串列上使用,不能在数字列上使用
3.DataFrame上没有str属性和处理方法
4.Series.str并不是python原生字符串,而是自己的一套方法,不过大部分和原生str很相似
字符串替换函数
df["bWendu"].str.replace("℃", "")
判断是不是数字
df["bWendu"].str.isnumeric()
使用str的startswith、contains等得到bool的Series可以做条件查询
df[df["ymd"].str.startswith("2018-03")]
链式操作,从月份中提取字符串"201803"
df["ymd"].str.replace("-", "").str[0:6]
正则替换
df["中文日期"].str.replace("[年月日]", "")
axis参数理解
axis=0或者axis="index":如果是单行操作,指的是某一行。如果是聚合操作,指的是跨行cross rows
axis=1或者axis="columns":如果是单列操作,指的是某一列。如果是聚合操作,指的是跨列cross columns
删除列
df.drop("列名", axis=1)
删除行
df.drop("行名", axis=0)
用index查询数据
df.set_index("userId", inplace=True, drop=False)
df.loc[500]
merge用法
pd.merge(left, right, how="inner", on="None", left_on=None, right_on=None)
数据合并concat
pd.concat([df1, df2], axis=0, join="outer", ignore_index=False) # outer:不匹配的也会展示
利用concat新增列
pd.concat([s1, df, s2], axis=1)
df.append(other, ignore_index=False) # append只能按行合并,相当于concat的简写形式
一行一行给df添加数据
pd.concat(
[pd.DataFrame([i]), columns=["A"] for i in range(5)], ignore_index=True
)
忽略报警
import warnings
warning.filterwarnings("ignore")
groupby分组统计
df.groupby("列名").sum()
df.groupby(["列1", "列2"]).sum()
列名不会变为行索引
df.groupby(["列1", "列2"], as_index=False).mean()
同时查看多个聚合函数
df.groupby("列1").agg([np.sum, np.mean, np.std])
查看单列的结果数据统计(2种方法)
df.groupby("列1")["列2"].agg([np.sum, np.mean, np.std])
df.groupby("列1").agg([np.sum, np.mean, np.std])["列2"]
不同列使用不用的聚合函数
df.groupby("列1").agg({"列2":np.sum, "列3":np.mean})
分层索引
unstack把二级索引变成列
ser.unstack()
把索引都变成列
ser.reset_index()
多层索引,可以用元组进行筛选
ser.loc["baidu"]
ser.loc["baidu", "2019-10-02"]
ser.loc[:, "2019-10-02"]
DataFrame设置分层索引
df.set_index(["公司", "日期"], inplace=True)
DataFrame筛选数据
当传入元组(key1,key2)时,代表筛选多层索引,key1是一级索引,key2是二级索引。比如key1=JD,key2=2019-10-02
当传入列表[key1, key2]时,代表同一层的多个KEY,key1和key2是并列的同级索引。比如key1=JD,key2=baidu
slice(None)代表筛选这一索引的所有内容
df.loc[(slice(None), ["2019-10-02", "2019-10-03"]), :]
把多级索引变为普通列
df.reset_index()
数据转换函数map、apply、applymap
map:只用于Series,实现每个值->值的映射
apply:用于Series实现每个值的处理,用于DataFrame实现某个轴的Series的处理
applymap:只能用于DataFrame,用于处理该DataFrame的每个元素
将股票代码英文转为中文
方法1:Series.map(dict)
dic = {"baidu":"百度", "ali":"阿里", "aqy":"爱奇艺", "jd":"京东"}
df["公司"].str.lower().map(dic)
方法2:Series.appy(function)
df["公司"].apply(lambda x: dic[x.lower()])
方法3:DataFrame.apply(function, axis=1),此时的x是一个Series
df.apply(lambda x: dic[x["公司"].lower()], axis=1)
applymap实现所有值的转换
df.applymap(lambda x: int(x))
对分组后的每个分组应用apply
df.groupby("列名").apply(function)
扩展:归一化
x_norm = (x - x.min()) / (x.max() - x.min())
pandas快速实现周、月、季度的日期聚合统计
将日期序列设置为行索引
筛选3月数据
df.loc["2020-03"]
周数字列表
df.index.week
月数字列表
df.index.month
季度数字列表
df.index.quarter
查看每周最高温度
df.groupby(df.index.week)["最高温度"].max()
pandas处理日期索引的缺失
将df的索引设置为日期索引
df.set_index(pd.to_datetime(df.index))
生成完整的日期序列
pdates = pd.date_range(start="2020-06-01", end="2020-06-20")
重置索引
df_new = df.reindex(pdates, fill_value=0)
重采样
df.resample("2D").mean() # 每2天采样求平均
pandas计算同比和环比
先把数据处理成:行索引为日期月格式df.resample("M"),values为一列
增加环比增长和同比增长列
df["环比增长"] = df["销售额"].pct_change(periods=1)
df["同比增长"] = df["销售额"].pct_change(periods=12)
浙公网安备 33010602011771号