本帖蚂蚁学Python之Pandas数据分析从入门到实战教程的笔记。
[Home]
1 初始Pandas
-
什么是Pandas
- 一个Python的开源类库,用于数据分析、处理、和格式化;
- 与其它类库配合使用,如Numpy, Scikt-learn。
-
安装
pip install pandas
-
演示方式:
jupyter notebook
[Home]
3 数据结构: DataFrame和Series
-
DataFrame
- 二维数组对象,查询数据就是由index查行,由columns查询列。
-
Series
1. Series
-
一维数组对象,由一组数据(可以为不同类型)和一组相对应的数据标签(即索引)组成。
-
创建方法pd.Series
- 用一个列表,及一个相对应的索引列表(可选)
s = pd.Series([1,2,'a',[1,2,3]], index=['a', 'b', 'c', 'd'])
- 用一个字典,在创建值的同时,指定其索引
dict_data = {'Ohio':35000,'Texas':72000,'Orgeon':16000,'Utah':5000} s= pd.Series(dict_data)
- 用一个列表,及一个相对应的索引列表(可选)
-
由标签索引或索引列表查询数据
s['a'] s[['b','a']]
2. DataFrame
-
表格型数据结构
- 每列可以是不同的值类型
- 即有行索引index,也有列索引columns
- 可以视为由Series组成的字典
-
创建方法pd.DataFrame
- 最常用的方法是从纯文本文件 、Excel文件、MySQL数据库中读取;
- 由多个字典序列创建,index可选,字典的键即为columns
dictdata = { 'state': ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Neveda'], 'year': [2000, 2001, 2002, 2001, 2002], 'pop': [1.5,1.7,3.6,4.3,9] } df = pd.DataFrame(dictdata, index=[1,2,3,4])
-
查询数据
- 如果只查询一列,返回的是pd.Series
- 如果查询多行、多列,返回的是pd.DataFrame
df['year'] df[['year', 'pop']] df.loc[1] # 注意pandas中的切片是包含末尾指标的,这一点不同于Python df.loc[1:3]
[Home]
4 数据查询的5种方法
Pandas主要查询方法中,本节主要讲述.loc方法。
- df.loc方法,根据行、列标签值查询(既能查询数据,又能覆盖写入,强烈推荐!)
- df.iloc方法,根据行、列的数字位置查询
- df.where方法
- df.query方法
1. 使用单个label值查询数据
# 得到单个值
df.loc["2018-01-03", "bWendu"]
# 得到Series
df.loc["2018-01-03", ["bWendu", "yWendu"]]
2. 使用值列表批量查询
```
df.loc[["2018-01-03","2018-01-05"], "bWendu"]
```
3. 使用数值区间进行范围查询
# 既包含开始,也包含结束
# 行index按区间
df.loc["2018-01-03": "2018-01-05", "bWendu"]
# 列index按区间
df.loc["2018-01-03", "bWendu":"fengxiang"]
4. 使用条件表达式查询
# 选出低于10度的记录
df.loc[df["yWendu"]<10,:]
5. 调用函数查询
# lamda函数
df.loc[lamda df : (df["bWendu"]<=30) & (df["yWndu"] > =15), :]
# 外部定义函数
def query_my_data(df):
...
df.loc[query_my_data,:]
- 相关链接
[Home]
5 Pandas新增数据列
1. 直接赋值
# "wencha"列原来是不存在
df.loc[:,"wencha"] = df["bWendu"] - df["yWndu"]
2. df.apply方法
Apply a function along an axis of the DatatFrame.
Objects passed to the fuction are Series objects whose index is either the DataFrame’s index(axis=0) or the DataFrame’s columns (axis=1).
# 定义函数
def get_wendu_type(x):
if x["bWendu"] > 33:
return "高温"
if x["yWendu"] < -10:
return "低温"
return "常温"
# 注意需要设置axis==1,这是series的index是columns
df.loc[:, "wendu_type"] = df.apply(get_wendu_type, axis=1)
3. df.assign方法
同时新增多个列。
Assign new columns to a DataFrame.
Rerturn a new object with all original columns in addition to new ones.
# 可以同时添加多个新的列
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"]="温差正常“
[Home]
6 数据统计函数
1. 汇总类统计
# 提取所有数字列统计结果
df.describe()
# 查看单个Serices数据
df["bWendu"].mean()
# 最高温
df["bWendu"].max()
# 最低温
df["bWendu"].min()
2. 唯一去重和按值计数
# 列出包含的值(去掉重复的值)
df['fengxiang'].unique()
# 列出各值出现的次数
df['fengxiang'].value_counts()
3. 相关系数和协方差
- 协方差,表两个向量间的同向或反向程度
- 相关系数,表两个向量间的相似程度
df.cov()
df.corr()
df['aqi'].corr(df['bWendu'])
7 缺失值处理
-
场景:对于没有规则的数据做清洁和整理
- 表格空行、空列
- 表格有合并
- 数据有缺失
-
处理前后对比
-
Pandas处理缺失值有3类函数
isnull
和notnull
:检测是否为空值,可用于dataframe和series;dropna
:丢弃、删除缺失值- axis:删除还是行还是列,(0 or ‘index’, 1 or ‘columns’, 默认0);
- how:如果等于any则任何值为空都删除,如果等于all则所有值为空才删除;
- inplace:如果为True则修改当关df,否则返回新的df;
- fillna:填充空值
- value:用于填充的值,可以是单个值,或者字典
- method:ffill(以前面的非空值填充)、bfill(以后面的非空值填充);
- inplace:True修改当前df,False返回新的df。
# 筛选出分类不为空的行 studf.loc[studf['分类'].notnull(), :] # 删除掉空列和空行 studf.dropna(axis="columns", how="all", inplace=True) studf.dropna(axis="index", how="all", inplace=True) # 将分数列为空的值填充为0 studf.fillna({"分数": 0}) studf.loc[:, '分数'] = studf['分数'].fillna(0) # 将姓名的缺失值填弃 studf.loc[:, '姓名'] = studf['姓名'].fillna(method='ffill') # 存成Excel表,不留存索引列 studf.to_excel(..., index=False)
[Home]
8 SettingsCopyWarning报警
-
Warning raised when trying to set on a copied slice from a
DataFrame
. -
核心要决:pandas的dataframe修改操作,只允许在源dataframe上进行,不得在copy上操作。
-
复现
condition = df['ymd'].str.startwith('20198-03'] df[condtion]['wen_cha']=df['bWendu']-df['yWendu'] # 产生SettingsCopyWarning报警
-
原因
df[condtion]['wen_cha']
相关于先get后set,此时get得到的是一个copy,而非一个view,则set时就会报警。pandas不允许在copy上进行修改。 -
修改
df.loc[condition, 'wen_cha'] = df['bWendu']- df['yWendu']
-
总结
- pandas不允许先筛选子dataframe,再进行修改写入。即不能先get,再set。
- 只能一次到位。
[Home]
9 数据排序
1.Series的排序
用法:Series.sort_values(ascending=True,inplace=False)
- asceding:默认True为升序排列,False为降序排列;
- inplace:是否修改为原始Series;
# 数字Series的升序排列
df["aqi"].sort_values()
# 数字Series的降序排列
df["aqi"].sort_values(ascending=False)
# 除对数字排序外还可对中文的Series列进行排序
df["tianqi"].sort_values()
2.DataFrame的排序
用法:DataFrame.sort_values(ascending=True,inplace=False)
- by:可以是单列排序和多列排序,亦可以是字符串或者List<字符串>;
- asceding:bool或List,升序还是降序,其中List对应by的多列;
- inplace:是否修改为原始DataFrame;
-
单列排序
# 对单个列进行升序 df.sort_value(by="aqi") # 对单个列进行降序 df.sort_values(by="aqi",ascending=False)
-
多列排序
# 按照空气质量等级、最高温度升序排列 df.sort_values(by=["aqiLevel","bWendu"]) # 按照空气质量等级、最高温度降序排列 df.sort_values(by=["aqiLevel","bWendu"],ascending=False) # 分别对空气质量等级、最高温度指定升序排列或者降序排列 df.sort_values(by=["aqiLevel","bWendu"],ascending=[Ture,False])
10 字符串处理
1.获取serise的str属性,使用各种字符串处理函数
# 获取erise的str属性
df["bWendu"].str
# 字符串替换函数
df["bWendu"].str.replace("C","")
# 判断是否为数字
df["bWendu"].str.isnumberic()
2.获取str属性用于bool条件查询
# 获取erise的str属性
condition=df["ymd"].str.startswith("2018-03")
df[condition].head()
3.简化多次str处理方法
# slice是切片语法
df["ymd"].str.replace("-","").str.slice[0:6]
4.正则表达式处理
# 添加新列
def get_nisnyueri(X):
year,month,day = X["ymd"].split("-")
return f"{year}年{month}月{day}日"
df["中文日期"] = df.apply(get_nianyueri,axis=1)
#去除插入列的文字
# 方法1:链式replace
df["中文日期"] .str.replace("年","") .str.replace("月","").str.replace("日","")
# 方法2:正则表达式替换
df["中文日期"] .str.replace("[年月日"],"")
- 相关链接
11 理解axis
- axis=0或者"index"
- 如果是单行操作,就指某一行;
- 如果是聚合操作,指的是跨行cross rows;
- axis=1或者"columns"
- 如果是单列操作,就指某一列;
- 如果是聚合操作,指的是跨列cross columns;
按照哪一个axis,就是这个axis要动起来(类似被for遍历),其它的axis保持不动
# 案例数据
df = pd.DataFrame(
np.arange(12).reshape(3,4),
columns = ["A","B","C","D"]
)
1.单列drop,就是删除某一列
# 删除某一列
df.drop("A",axis = 1)
2.单列drop,就是删除某一行
# 删除某一行
df.drop(1,axis = 0)
3.按axis=0/index执行mean聚合操作(注意:输出每列的结果)
# axis = 0或axis = index
df.mean(axis = 0)
4.按axis=1/columns执行mean聚合操作(注意:输出每行的结果)
# axis = 1或axis = columns
df.mean(axis = 1)
5.增加列等于其他四列的和
# 增加列=其他四列的和
def get_sum_value(x):
return x["A"]+x["B"]+x["C"]+x["D"]
df["sum__value"] = df.apply(get_sum_value,axis = 1)
12 index用途
1.查询数据
# 使用index方法查询
df.loc[800].head(5)
2.提升查询性能
- 如果index是唯一的,pandas使用哈希表优化,查询性能为O(1);
- 如果index不是唯一的,但是有序的,pandas使用二分法查找,查询性能为O(logN);
- 如果index是完全随机的,每次查询需要全表搜索,查询性能为O(N);
# 使用index排序后的查询
df_sorted = df_shuffile.sort_index(4)
3.自动对齐数据
# 对齐数据
s1=pd.Series([1,2,3],index=list("abc"))
s2=pd.Series([2,3,4],index=list("bcd"))
s1+s2
4.强大的数据结构支持
- Categoricallndex,基于分类数据的index,提升性能;
- MultiIndex,多维索引,用于groupby多维聚合后结果等;
- DatetimeIndex,时间类型索引,强大的日期和时间的方法支持;
[Home]
13 Merge
1.数量的对齐关系
- 一对一关系的merge
pd.merge (left,right,on='sno')
- 一对多关系的merge
# 数目以多的一边为准(数量会被复制)
pd.merge (left,right,on='sno')
- 多对多关系的merge
# 数目以多的一边为准(数量会出现乘法)
pd.merge (left,right,on='sno')
2.left、right、inner、outer join的区别
# 左、右边都有key则出现在结果里
pd.merge (left,right,bow='inner')
# 左边的key输出结果,右边无法匹配则为Null
pd.merge (left,right,bow='left')
# 右边的key输出结果,左边无法匹配则为Null
pd.merge (left,right,bow='right')
# 左边、右边都出现结果,如果无法匹配则为Null
pd.merge (left,right,bow='outer')
3.非key字段重名
# 左边、右边都出现结果,如果无法匹配则为Null
pd.merge (left,right,on='key')
#或者自己指定后缀
pd.merge (left,right,on='key',suffixes=('_left','_right'))
- 相关链接
[Home]
14 Concat合并
1.pandas.concat合并数据
pd.concat([df1,df2])
# ignore_index=True(忽略)
pd.concat([df1,df2],ignore_index=True)
# join=inner(过滤)
pd.concat([df1,df2],ignore_index=True,join="inner")
# 添加一列Series
s1=pd.series(list(range(4)),name="F")
pd.concat([df1,s1,axis=1)
# 添加多列Series
s2=df1.apply(lambda x:x["A"]+"_GG",axis=1)
# 列表只有series
pd.concat([s1,s2],axis=1)
# 列表混合顺序
pd.concat([s1,df1,s2],axis=1)
2.DataFrame.appent按行合并数据
# 给一个dataframe添加dataframe
df1 = append(df2)
# ignore_index=True(忽略)
df1.append(df2,ignore_index=True)
# 一行一行为ataframe添加数据
df=pd.DataFrame(columns=["A"])
[Home]
15 批量拆分与合并Excel文件
1.大Excel文件等分拆多个Excel
- 使用df.iloc方法,将一个大的dataframe拆分为多个小的文件
- 使用dataframe_to_excel保存每个小的excel
2.合并多个Excel
- 遍历文件夹,合并想要Excel文件列表
- 读取dataframe,给每个df添加一列用于标记来源
- 使用pd.concat进行合并
- 将合并文件输出到Excel
[Home]
16 分组数据处理
1.使用聚合函数统计数据
#单个列groupby查询数据统计
df.groupby("A").sum()
#多个列groupby查询数据统计
df.groupby(["A","B"]).as_index=False)mean()
# 同时查看多种数据统计
df.groupby("A").agg([np.sum,np.mean,np.std])
# 查看单列统计结果
df.groupby("A").agg([np.sum,np.mean,np.std])["C"]
# 不同列使用不同聚合函数
df.groupby("A").agg(["C":np.sum,"D":np.mean])
2.遍历groupby理解执行流程
# 遍历单个分组数据
g=df.groupby("A")
# 遍历多个列聚合分组
g=df.groupby(["A","B"])
# 查询group某几列生成series或者dataframe
g["C"]
[Home]
17 分层索引Multiindex
1.series的分层索引MultiIndex
ser.reset_index()
2.series多层索引筛选数据
# 第一层索引
ser.loc["BAIDU"]
# 多层索引,用元组形式筛选
ser.loc[("BAIDU","2019-10")]
# 筛选第二层索引
ser.loc[(:,"2019-10")]
3.DataFramed 多层索引MultiIndex
stocks.sort_index(inplace = True)
stocks
4.DataFramed 多层索引筛选数据
- 元组(key1/key2)代表筛选多层索引,其中key1索引第一层,key2索引第二层
- 列表(key1/key2)代表同一层的多个key,其中key1和key2是并列的同级索引
stocks.loc[(slice(None),["2019-10-02","2019-10-03"]),:]
[Home]
18 map-apply-applymap数据处理
- map:只用于Series,实现每个值-值的映射
- apply:用于Series实现每个值的处理,用于DataFrame实现某个轴的Series的处理
- applymap:只能用于DataFrame,用于处理DataFrame的每个元素
1.map用于Series值的转换
# 使用字典映射或者函数映射
Series.map(dict)或者Series.map(function)
#以将股票代码英文转换为中文名字为例
#使用dict
stocks["公司中文1"] = stocks["公司"].str.lower().map(dict_company_names)
#使用函function
stocks["公司中文2"] = stocks["公司"].map(lambda x:dict_company_names[x.lpwer()])
2.apply用于Series、DataFrame的转换
- Series.apply(function),函数的参数为每个值
- DataFrame.apply(function),函数的参数是Series
注意:
- 1.apply在stocks这个DataFrame上调用;
- 2.lambda x的x是Series,因为指定了axis=1;
# Series.apply(function)
stocks["公司中文3"] = stocks["公司"].apply(lambda x:dict_company_names[x.lpwer()])
# DataFrame.apply(function)
stocks["公司中文4"] = stocks.apply(lambda x:dict_company_names[x["公司"].lpwer()],axis=1)
3.applymap用于DataFrame所有值的转换
# 将数值取整用于元素
sub_df.applymap(lambda x:int())
# 直接修改原df的几列
stocks.loc[:,['收盘','开盘','高','低']]= sub_df.applymap(lambda x :int(x))
[Home]
19 groupby每个分组的apply
- function的第一个参数是dataframe
- function返回结果可以是dataframe、series、单个值或者与输入dataframe完全没关系
1.按照分组将数值归一化
归一化的定义:
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"].head]()
2.提取每组TOPN数据
# 获取某年每个月温度最高的2天数据
def getWenduTopN(df,topn)
# df指每个月份分组groupby的df
return df.sort_values(by - "bWendu")[["ynd","bWendu"]][-topn:]
df.groupby("month").apply(getWenduTopN,topn = 2.head)