当前位置:   article > 正文

强大的数据分析工具——Pandas操作、易错点、知识点三万字详解_df setindex

df setindex

一、 Pandas数据结构

1.Series
2.DataFrame
3.从DataFrame中查询出Series

DataFrame: 二维数据、整个表格、多行多列

9262c6a37f2c4dfc9ff211e99d6767c0.png

Series:一维数据,一行或者一列 

a8e26ded8b4d484f9a12cfd8891c7288.png

  1. import pandas as pd
  2. import numpy as np

 

1、Series

Series是一种类似于一维数组的对象,它由一组数据〈不同数据类型)以及一组与之相关的数据标签(即索引)组成。

1.1仅有数据列表即可产生最简单的Series

左侧为索引,右侧为数据

  1. s1=pd.Series([1,'x',5.7,7])
  2. #左侧为索引,右侧为数据
  3. s1

获取索引
s1.index

  1. 获取索引
  2. s1.index

获取数据
s1.values

  1. #获取数据
  2. s1.values

bb96f75758ae47069df2684fca9e4379.png

1.2创建一个具有标签索引的Series 

  1. s2=pd.Series([1,'x',5.7,7],index=['d','b','a','c'])
  2. s2
  3. s2.index

105cd540c4ef42f0ad1090dca21b268a.png

1.3使用python字典创建Series

python字典和seires有着密不可分的关系

  1. sdata={'apple':35,'tex':40,'bananan':20,'pearl':30}
  2. s3=pd.Series(sdata)
  3. s3

 fe15888a39b7492faff9dec582f76266.png

1.4根据标签索引查询数据

----类似pthon的字典dict

  1. s2
  2. s2['a']

 查一个数据得到是python原生的数据类型

  1. #查一个数据得到是python原生的数据类型
  2. type(s2['a'])
  3. s2[['b','a']]

查询Series的类型  type(s2[['b','a']])

  1. #查询Series的类型
  2. type(s2[['b','a']])

dbf8eb4a1fad4698a352c09a8ea223e8.png

2.DataFrame

DataFrame是一个表格型的数据结构

①每列可以是不同的值类型(数值、字符串、布尔值等)
②既有行索引index,也有列索引columns
③可以被看做由Series组成的字典
④创建dataframe最常用的方法,见读取纯文本文件、excel、mysql数据库

 

2.1根据多个字典序列创建dataframe

列表中每个值的个数都必须相同

  1. #列表中每个值都必须相同
  2. data={
  3. 'state':['apple','tex','txt','banana','cxv'],
  4. 'year':[2000,1999,1998,1997,1996],
  5. 'pop':[1.1,1.2,1.3,1.4,1.5]
  6. }
  7. df=pd.DataFrame(data)
  8. df
  1. df.dtypes
  2. df.columns
  3. df.index

6450cab34ec3408d8d0e7cdd60d3757e.png

 3.从DataFrame中查询出Series

    如果只查询一列,一行,返回的是pd.Series
    如果查询多行、多列,返回的是pd.DataFrame

df

4144a47a58df4c0cbf130557e36b7ade.png

3.1查询一列,结果是一个pd.Series 

  1. df['state']
  2. type(df['year'])

d483b9e6e28b44719c268a5024ce4d0c.png

3.2查询多列,结果是一个pd.DataFrame 

  1. df[['pop','year']]
  2. type(df[['pop','year']])

3368e20e76b249ba8448d594d28ba14c.png

3.3查询一行,结果是一个pd.Series 

loc(1)代表查询一行

  1. df.loc[1]
  2. type(df.loc[1])

3.4查询多行,结果是一个pd.DataFrame

列表中切片的操作方法去取,但是在Pandas中包括末尾元素

  1. #列表中切片的操作方法去取,但是在Pandas中包括末尾元素
  2. df.loc[1:3]
  3. type(df.loc[1:3])

7afd28dc54bb40e4ad8cf8bc1bb69ecb.png

 总结:
60843b869a5748c7aebe7b09b1a1463a.png

81ae818f42484eaba3f9fd2a2ed20253.png

 

二、Pandas数据读取

        f269be97029c403abea506fad63c1e87.png

        1. pandas读取纯文本文件
        ·读取csv文件
        ·读取csv文件
        2. pandas读取xlsx格式excel文件
        3. pandas读取mysql数据表 

1、读取纯文本文件

1.1读取CSV,使用默认的标题行、逗号分隔符

  1. import pandas as pd
  2. fpath="./datas/ml-latest-small/ratings.csv"
  3. #注意是反斜杠/,不然会报错

注意:地址中是反斜杠/,不然会报错

使用pd.read_csv读取数据

ratings=pd.read_csv(fpath)

查看前几行的数据
ratings.head()

  1. #查看前几行的数据
  2. ratings.head()

e6f8ae0996b5458ba80c095e1e5bb617.png

 

查看数据的形状,返回(行数,列数)ratings.shape

  1. #查看数据的形状,返回(行数,列数)
  2. ratings.shape

查看列名列表
ratings.columns

  1. #查看列名列表
  2. ratings.columns

查看索引列
ratings.index

  1. #查看索引列
  2. ratings.index

查看每列的数据类型
ratings.dtypes

  1. #查看每列的数据类型
  2. ratings.dtypes

8d3ecafa96a145a8b0df37fad68661ef.png

1.2 读取txt文件,自己指定分隔符、列名 

fpath2='./datas/crazyant/access_pvuv.txt'
  1. pvuv2=pd.read_csv(
  2. fpath2,
  3. sep='\t',
  4. header=None,
  5. names=['pdate','pv','pu']
  6. #注意设置列名的时候是names,而不是nameread_csv() got an unexpected keyword argument 'name'
  7. )
  8. pvuv2

注意:设置列名的时候是names,而不是name 报错:read_csv() got an unexpected keyword argument 'name'

c14edc564ab94277b3ca93f615ade78d.png

2、读取excel文件

  1. fpath3='./datas/crazyant/access_pvuv.xlsx'
  2. p3=pd.read_excel(fpath3)
  3. p3

9dcbc875d2de42808432f996cf780c04.png

3、读取MySQL数据库 

  1. !pip install pymysql
  2. #使用的方法是read_sql
  3. import pymysql

使用的方法是read_sql:

  1. coon=pymysql.connect(
  2. host='127.0.0.1',
  3. user='root',
  4. database='test'
  5. charset='utf-8'
  6. )
  7. mysql_page=pd.read_sql('select * form crazyant_pvuv',con=coon)

注意:host是数据库的本地连接,user都是你本地电脑中设置的参数

 

三、Pandas查询数据

Pandas查询数据的几种方法

1.df.loc方法,根据行、列的标签值查询

2. df.iloc方法,根据行、列的数字位置查询

3. df.where方法

4. df.query方法

.loc既能查询,又能覆盖写入,强烈推荐!

Pandas使用df.loc查询数据的方法

1.使用单个label值查询数据

2.使用值列表批量查询

3.使用数值区间进行范围查询

4.使用条件表达式查询

5.调用函数查询

·以上查询方法,既适用于行,也适用于列·注意观察降维dataFrame>Series>值

import pandas as pd

1、读取数据

北京2018年全年天气预报

  1. df=pd.read_csv('./datas/beijing_tianqi/beijing_tianqi_2018.csv',index_col='ymd')
  2. df.head()
  3. df.index

d67f39280ca74207bb82d4b6092933c0.png

设置索引为日期,方便按日期筛选
inplace=True 表示直接在原存储空间上进行更改,不是重新开辟一块空间进行更改
 

  1. #设置索引为日期,方便按日期筛选
  2. #inplace=True 表示直接在原存储空间上进行更改,不是重新开辟一块空间进行更改
  3. df.set_index('ymd',inplace=True)
  4. df.head()

503518185e824759a088e6c57ed68743.png

替换掉温度后的℃
其实还是使用切片操作,首先筛选出所有的行,在筛选出yWendu中一列,带着类型replace修改完之后,在对修改后的类型进行转换 

  1. df.loc[:,'bWendu']=df['bWendu'].str.replace('℃','').astype('int32')
  2. df.loc[:,'yWendu']=df['yWendu'].str.replace('℃','').astype('int32')
  3. df.head()
  4. df.dtypes

aea2d976239a416c979866cc3002f766.png

 值得注意的是:

AttributeError: Can only use .str accessor with string values!这种错误一般都是修改完之后了,不能在进行修改,说明已经修改过了

2、使用单个label值查询数据

行或列,都可以只传入单个值,实现精确匹配

 

查询一个单元格,只会返回一个数字值

  1. #查询一个单元格,只会返回一个数字值
  2. df.loc['2018-01-01','bWendu']

对于列的筛选,会产生一列,得到一个Series

  1. #对于列的筛选,会产生一列,得到一个Series
  2. df.loc['2018-01-01',['bWendu','yWendu']]

8ee2d87bcc5849898840b98f06c585b9.png

3、使用值列表批量查询 

得到Series

  1. #得到Series
  2. df.loc[['2018-01-02','2018-01-03','2018-01-04'],'bWendu']

得到DataFrame

  1. #得到DataFrame
  2. df.loc[['2018-01-02','2018-01-03','2018-01-04'],['bWendu','yWendu']]

6af0f49c7cd9456f99a2b5c26766b76f.png

 

4、使用数值区间进行范围查询

注意:区间既包括开始,也包括结束

行index按区间,切片操作的时候不用加双【】

列index按区间

行和列都按区间查询

  1. #行index按区间,切片操作的时候不用加双【】
  2. df.loc['2018-01-03':'2018-01-05','bWendu']
  1. #列index按区间
  2. df.loc['2018-01-03','bWendu':'fengxiang']
  1. #行和列都按区间查询
  2. df.loc['2018-01-03':'2018-01-05','bWendu':'fengxiang']

603ad36b51484cd7b9dd285d81431d2e.png

 

5、使用条件表达式查询

bool列表的长度等于行数或者列数

简单条件查询,最低温度低于-10度的列表

  1. #简单条件查询,最低温度低于-10度的列表
  2. df.loc[df['yWendu']<-10,:]

观察这里的boolean条件

  1. #观察这里的boolean条件
  2. df['yWendu']<-10

a02c9f34370c46fb8dedefe00fbfa0ec.png

 

复杂条件查询,查完美天气

注意,组合条件&符号合并,每个条件判断都得带括号

查询最高温度小于30度,最低温度大于15度,晴天,天气为优的数据

  1. #查询最高温度小于30度,最低温度大于15度,晴天,天气为优的数据
  2. df.loc[(df['bWendu']<=30) & (df['yWendu']>=15) & (df['tianqi']=='晴') & (df['aqiLevel']==1),:]

观察这里boolean的条件

  1. #观察这里boolean的条件
  2. (df['bWendu']<=30) & (df['yWendu']>=15) & (df['tianqi']=='晴') & (df['aqiLevel']==1)

e73d5aa201cb432f8f75da27dfc18e9f.png

 6、调用函数查询

直接写lambda表达式

  1. # 直接写lambda表达式
  2. df.loc[lambda df :(df['bWendu']<=30)&(df['yWendu']>=15),:]

直接编写函数,查询9月份,空气质量好的数据

  1. #直接编写函数,查询9月份,空气质量好的数据
  2. def query_mydata(df):
  3. return df.index.str.startswith('2018-09')&df['aqiLevel']==1
  4. df.loc[query_mydata]

7ce900a53af2485ea542be782eea62e9.png

 

de8088810670481190e40a0de8ad7781.png

 

注意:

函数式编程的本质:函数自身可以像变量一样传递

 

四、 Pandas怎样新增数据列?

在进行数据分析时,经常需要按照一定条件创建新的数据列,然后进行进一步分析

1.直接赋值
2. df.apply方法
3. df.assign方法
4.按条件选择分组分别赋值

import pandas as pd

1、读取CSV数据到dataframe

  1. fpath='./datas/beijing_tianqi/beijing_tianqi_2018.csv'
  2. df=pd.read_csv(fpath)
  3. df.head()

1c1e08521e9141e7b51a013e5454ef2e.png

2、对数据进行一个预处理 

清理温度列,变成一个数字类型

  1. df.loc[:,'bWendu']=df['bWendu'].str.replace('℃','').astype('int32')
  2. df.loc[:,'yWendu']=df['yWendu'].str.replace('℃','').astype('int32')
  3. df.head()
  4. #AttributeError: Can only use .str accessor with string values! 这种情况下语句代码只能运行一次,当运行第二次的时候,原存储的数据已经被改变了

需要注意的是:AttributeError: Can only use .str accessor with string values!  这种情况下语句代码只能运行一次,当运行第二次的时候,原存储的数据已经被改变了

3、直接赋值方法

将温差加入表格当中,注意wencha是一个series,后面的减法返回的是一个series

  1. df.loc[:,'wencha']=df['bWendu']-df['yWendu']
  2. df.head()

5be21d4f4893476dabc4173a67fe1ce9.png

4、df.apply方法 

Apply a function along an axis of the DataFrame.
Objects passed to the function are Series objects whose index is either the DataFrame's index(axis=0) or the DataFrame's columns (axis=1).

实例:添加─列温度类型:
        1.如果最高温度大于33度就是高温
        2.低于-10度是低温
        3.否则是常温

  1. def get_wendutype(x):
  2. if x['bWendu']>33:
  3. return '高温'
  4. if x['yWendu']<-10:
  5. return'低温'
  6. else:
  7. return '常温'
  8. df.loc[:,'wendutype']=df.apply(get_wendutype,axis=1)
df['wendutype'].value_counts()

6282c2b44a02434fb28dfbffb9180d58.png

5、df.assign方法 

Assign new columns to a DataFrame.
Returns a new object with all original columns in addition to new ones.

实例:将温度从摄氏度变成华氏度

注意:df.assign可以同时添加多个列

  1. #df.assign可以同时添加多个列
  2. df.assign(
  3. yWendu_huashi=lambda x: x['yWendu']*9/5+32,
  4. bWendu_huashi=lambda x: x['bWendu']*9/5+32
  5. )

b16c063b2aaf4f75ade935373c110f4a.png

6、按条件选择分组分别赋值

按条件先选择数据,然后对这部分数据赋值新列

实例:高低温差大于10度,则认为温差大

  1. #先创建空列(第一种创建新列的方法)
  2. df['wencha']=''
  3. df.loc[df['bWendu']-df['yWendu']>10,'wencha']='温差大'
  4. df.loc[df['bWendu']-df['yWendu']<=10,'wencha']='温差正常'
  5. df['wencha'].value_counts()

567e1c4e9e2d44b297dcfc3baeaa7320.png

 

五、Pandas 数据统计函数

1、汇总类统计

2、唯一去重和按值计数

3、相关系数和协方差

import pandas as pd

1、预备步骤,对数据进行读取和预处理(将温度都改为Int类型)

  1. fpath='./datas/beijing_tianqi/beijing_tianqi_2018.csv'
  2. df=pd.read_csv(fpath)
  3. df.head()

8457fb1d579e43b788e062f0c35de730.png

 

  1. df.loc[:,'bWendu']=df['bWendu'].str.replace('℃','').astype('int32')
  2. df.loc[:,'yWendu']=df['yWendu'].str.replace('℃','').astype('int32')
  3. df.head()

b5d2fd7de27e4e78a4a3a7d801c017cb.png

2、对数据进行汇总类统计 

  1. #提取出所有数字列统计结果
  2. df.describe()

0110f1dea51e4c3cb055a21db43c3d54.png

查看单个Series的数据---最高温度的平均值---df['bWendu'].mean() 

  1. # 查看单个Series的数据---最高温度的平均值
  2. df['bWendu'].mean()

查看最高温度----df['bWendu'].max()

  1. #查看最高温度
  2. df['bWendu'].max()

最低温度----df['yWendu'].min()

  1. #最低温度
  2. df['yWendu'].min()

b02689b019f34e0eb6f5bcd4b32ea57d.png

3、唯一去重和按值计算

3.1唯一去重性

一般不用于数值列,而是枚举,分类列-----df[“  ” ].unique()

  1. df['fengxiang'].unique()
  2. df['tianqi'].unique()
  3. df['fengli'].unique()

 47e6cd9e001243dd8d8c6b1fbc04e622.png

3.2 按值计数(对数据探索十分有用)  

  1. df['fengxiang'].value_counts()
  2. df['tianqi'].value_counts()
  3. df['fengli'].value_counts()

b7435af183aa469ba7cafedfae8a35ab.png

828347c214f84cf2a8645ce48f33f9b3.png

5、相关系数和协方差用途(超级厉害)︰

1.两只股票,是不是同涨同跌?程度多大?正相关还是负相关?

2.产品销量的波动,跟哪些因素正相关、负相关,程度有多大?

对于两个变量X、Y:

1.协方差︰衡量同向反向程度,如果协方差为正,说明X,Y同向变化,协方差越大说明同向程度越高;如果协方差为负,说明×,Y反向运动,协方差越小说明反向程度越高。

2.相关系数:衡量相似度程度,当他们的相关系数为1时,说明两个变量变化时的正向相似度最大,当相关系数为- 1时,说明两个变量变化的反向相似度最大

 协方差矩阵-----df.cov()

  1. #协方差矩阵
  2. df.cov()

相关系数矩阵----df.corr()

  1. #相关系数矩阵
  2. df.corr()

单独查看空气质量和最高温度的相关系数----df['aqi'].corr(df['bWendu'])

  1. #单独查看空气质量和最高温度的相关系数
  2. df['aqi'].corr(df['bWendu'])
  3. df['aqi'].corr(df['yWendu'])

检测空气质量和温差的相关系数----df['aqi'].corr(df['bWendu']-df['yWendu'])

  1. #检测空气质量和温差的相关系数
  2. df['aqi'].corr(df['bWendu']-df['yWendu'])

8cbf85016ded4dc2983d512aced4b255.png

8f0eeaed85e84436aa69c04bb9a8e048.png

以上就是特征方程对于机器学习重要性的一个例子 

注:什么是特征方程?

特征方程是为研究相应的数学对象而引入的一些等式,它因数学对象不同而不同,包括数列特征方程、矩阵特征方程、微分方程特征方程、积分方程特征方程等等。

下面所介绍的仅仅是数列的特征方程。

一个数列:

        711f6e58f09d4aa2a7ba0647f234e253.png

 

 

设 有r,s使

5a02e0ec79ad4eafa78a989b4df041cc.png

 

 

所以

d466bdcf29b94d83a4f1e4a6a94c1192.png

 

 

e86baae5d86e4d9da706475d5a347614.png

消去s就导出特征方程式

18d3da59d1d94cda9f4effa84a7f9d50.png

六、Pandas 三类函数对缺失值的处理

Pandas使用这些函数处理缺失值:

. isnull和notnull:检测是否是空值,可用于df和series. 
    dropna:丢弃、删除缺失值
         axis:删除行还是列,{0 or 'index',1 or 'columns'}, default 0
         how :如果等于any则任何值为空都删除,如果等于all则所有值都为空才删除
        inplace :如果为True则修改当前df,否则返回新的df
    . fillna:填充空值
         value:用于填充的值,可以是单个值,或者字典(key是列名,value是值)
         method :等于ffill使用前一个不为空的值填充forword fill;等于bfill使用后一个不为空的值填充backword fill
         axis:按行还是列填充,{0 or 'index',1 or 'columns'}
        inplace:如果为True则修改当前df,否则返回新的df

import pandas as pd

1、实例:特殊Excel的读取、清洗、处理

步骤1:读取excel的时候,忽略前几个空行

  1. fpath='./datas/student_excel/student_excel.xlsx'
  2. df=pd.read_excel(fpath,skiprows=2)
  3. df

1056af5e924e467599574f17912d8a72.png

步骤2:检测空值--df.isnull()

df.isnull()

6deb5c4936b645dbad7e9d953ef4bf69.png

 以下两个函数输出的是相反的值:

df['分数'].isnull()、df['分数'].notnull()

  1. df['分数'].isnull()
  2. df['分数'].notnull()

6011b19e01cc45b3bb1e73f10a446958.png

筛选出没有空分数的所有行---df.loc[df['分数'].notnull(),:] 

  1. #筛选出没有空分数的所有行
  2. df.loc[df['分数'].notnull(),:]

752aae9ba73c4987982f1a1d73c8911f.png

 步骤3:删除掉全是空值的列

  1. df.dropna(axis='columns',how='all',inplace=True)
  2. df

5e65eccb482b4fd7917223edae1f4172.png

步骤4:删除掉全是空值的行 

  1. df.dropna(axis='index',how='all',inplace=True)
  2. df

9200632f34bf40f7943e3035703f168d.png

步骤5:将分数列为空的填充为0分 

df.fillna({'分数':0})

b28e757383c145c4b189c94026867379.png

 上述操作可以等于以下代码

  1. #上述操作可以等于一下代码
  2. df.loc[:,'分数']=df['分数'].fillna(0)
  3. df

64cac57ea73e4d3a82e46c1f1f422ed4.png

 步骤6:将姓名的缺失值填充

使用前面的有效值填充,用ffill:forward fill

  1. df.loc[:,'姓名']=df['姓名'].fillna(method='ffill')
  2. df

b2e280752ea2429d8d29acd4554dce6a.png

 步骤7:将清洗号的excel保存

df.to_excel('./datas/student_excel/student_excel_clean.xlsx',index=False)

七、Pandas 的SettingWithCopyWarning 报警复现、原因、解决方案

1、读取数据并对数据进行预处理操作

  1. fpath='./datas/beijing_tianqi/beijing_tianqi_2018.csv'
  2. df=pd.read_csv(fpath)
  3. df.head()
  4. df

cfa2cebfab444ab6bb15835712d603de.png

  1. import pandas as pd
  2. df.loc[:,'bWendu']=df['bWendu'].str.replace('℃','').astype('int32')
  3. df.loc[:,'yWendu']=df['yWendu'].str.replace('℃','').astype('int32')
  4. df

 998092fb37b541078e67683a32073537.png

2、复现错误 

只选出3月份的数据用来分析

  1. #只选出3月份的数据用来分析
  2. condition=df['ymd'].str.startswith('2018-03')

设置温差

  1. #设置温差
  2. df[condition]['wen_cha']=df['bWendu']-df['yWendu']

900f602bd40048689caac587de3f183e.png

值得注意的是报错: 

SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead
 发现:df[condition]['wen_cha']=df['bWendu']-df['yWendu']改句代码出错

这里我们也可以查看官网网站去完成差错:Indexing and selecting data — pandas 1.4.4 documentation (pydata.org)

查看是否修改成功

  1. #查看是否修改成功
  2. df[condition].head()

048cd9a71153457b93e605c781c38647.png

 3、原因

发出警告的代码: df[condition]['wen_cha']=df['bWendu']-df['yWendu']
相当于: df.get(condition).set(wen_cha),第一步的get发出了报警
链式操作其实是两个步骤,先get 后set,get得到的dateframe可能是View也可能是Copy、Pandas发出警告
【先可以去官网查看原因】

核心: pandas的dataframe的修改写操作,只允许在dataframe上进行,一步到位

 

4、解决方法1

将get+set 的两步操作,改成set的一步操作

  1. df.loc[condition,'wen_cha']=df['bWendu']-df['yWendu']
  2. df.head()
df[condition].head()

cb56594ef3de4fccb115d8432f905655.png

 5、解决方法2

如果需要预选筛选数据做后续的处理分析,使用copy复制Dataframe

  1. df_month3=df[condition].copy()
  2. df_month3.head()

b9c5ff9f951349b09e637adc40f715b3.png

  1. df_month3['wen_cha']=df['bWendu']-df['yWendu']
  2. df_month3.head()

 10a22312686a445cb433ef7c212dd9b7.png

八、Pandas数据排序【Series和DataFrame的排序操作函数】

1、Pandas数据排序:

Series的排序:
    Series.sort_values(ascending=True, inplace=False)

参数说明:
    ascending:默认为True升序排序,为False降序排序.
    inplace:是否修改原始Series

DataFrame的排序:
    DataFrame.sort_values(by, ascending=True, inplace=False)

参数说明:
    by:字符串或者List<字符串>,单列排序或者多列排序
    ascending: bool或者List,升序还是降序,如果是list对应by的多列. 
    inplace:是否修改原始DataFrame

1.1、对数据进行读取和处理操作

  1. import pandas as pd
  2. fpath='./datas/beijing_tianqi/beijing_tianqi_2018.csv'
  3. df=pd.read_csv(fpath)
  4. df

22d5f4a6daf34699b7adb26360438f04.png

 

  1. df.loc[:,'bWendu']=df['bWendu'].str.replace('℃','').astype('int32')
  2. df.loc[:,'yWendu']=df['yWendu'].str.replace('℃','').astype('int32
df.head()

a28c982cb06e4e5f8315d153619d426d.png

2、Series排序

df['aqi'].sort_values(ascending=False)

  1. ### 2、Series排序
  2. df['aqi'].sort_values(ascending=False)

0a6f7b3cdef849fba1e7b45933643f40.png 

默认为从低到高进行排序     df['aqi'].sort_values()

  1. #默认为从低到高进行排序
  2. df['aqi'].sort_values()

cc24cb5a9cfa4dce90a7392c86a3160a.png

也可以对非数字序列进行排序——下述演示的是字符串序列进行排序   df['tianqi'].sort_values() 

  1. #也可以对非数字序列进行排序——下述演示的是字符串序列进行排序
  2. df['tianqi'].sort_values()

7cf8594548e2439da31fec34dfdc21aa.png

3、DataFrame的排序

3.1 单列排序

默认天气状况从低到高进行排序   df.sort_values(by='aqi')

  1. #默认天气状况从低到高进行排序
  2. df.sort_values(by='aqi')

5b3049fdeb0d4644a914694c4973625c.png

df.sort_values(by='aqi',ascending=False)

 8b85d7c582b64572bcb306c2d68efb4b.png

3.2多列排序 

 按空气质量等级、最高温度排序、默认升序

  1. #按空气质量等级、最高温度排序、默认升序
  2. df.sort_values(by=['aqiLevel','bWendu'])

0a26a5482e7c45e9885ef3b151c0aef8.png

两个字段都是降序排序  df.sort_values(by=['aqiLevel','bWendu'],ascending=False)

  1. #两个字段都是降序排序
  2. df.sort_values(by=['aqiLevel','bWendu'],ascending=False)

e1bd094cc2634f2bb283c750839ac72a.png

分别指定升序和降序
df.sort_values(by=['aqiLevel','bWendu'],ascending=[True,False]

  1. #分别指定升序和降序
  2. df.sort_values(by=['aqiLevel','bWendu'],ascending=[True,False])

af3e14ae4adb49fe9916520c2f8d2543.png

 

九、Pandas 的字符串处理操作

 0、Pandas字符串处理

前面我们已经使用了字符串的处理函数:
    df["bWendu"].str.replace("℃","").astype('int32')Pandas的字符串处理:

1.使用方法:先获取Series的str属性,然后在属性上调用函数;

2.只能在字符串列上使用,不能数字列上使用;

3. Dataframe上没有str属性和处理方法

4.Series.str并不是Python原生字符串,而是自己的一套方法,不过大部分和原生str很相似;

内容如下:

1.获取Series的str属性,然后使用各种字符串处理函数

2.使用str的startswith、contains等bool类Series可以做条件查询

3.需要多次str处理的链式操作

4.使用正则表达式的处理

1、分步骤读取数据

  1. import pandas as pd
  2. fpath='./datas/beijing_tianqi/beijing_tianqi_2018.csv'
  3. df=pd.read_csv(fpath)
  4. df.head()

12b5169e8d6348d0af4ba8b3d06b45ad.png

df.dtypes

c8b58ee04f1444fbaa04594bd6f4e12f.png

 2、获取Series的str属性,使用各种字符串处理函数

获取最高温度的Series的温度列

  1. #获取最高温度的Series的温度列
  2. df['bWendu'].str

6e507b713a064a0f91ff0b7128a3c4f0.png

 

字符串替换函数

  1. #字符串替换函数
  2. df['bWendu'].str.replace('℃','')

bfc56c46ad814362ae9c52394c81ae73.png

 

判断是不是数字

  1. #判断是不是数字
  2. df['bWendu'].str.isnumeric()


684ce5783c5c403696c4c02b05691362.png

 

  1. df['aqi'].str.len()
  2. #AttributeError: Can only use .str accessor with string values! len()方法只能用于字符串类型的数据

AttributeError: Can only use .str accessor with string values!  len()方法只能用于字符串类型的数据

3、使用str 的startwith、contains等得到bool的Series可以做条件查询

Pandas startswith()是另一种在系列或 DataFrame 中搜索和过滤文本数据的方法。此方法类似于Python的startswith()方法,但参数不同,并且仅适用于Pandas对象。因此,.str必须在每次调用此方法之前加上前缀,以便编译器知道它与默认函数不同。

用法:Series.str.startswith(pat, na=nan)

参数:
pat:要搜索的字符串。 (不接受正则表达式)
na:用于设置序列中的值为NULL时应显示的内容。

返回类型:布尔序列,为True,其中值的开头是传递的字符串。

从ymd这一列挑选出2018-03这类型的数据,返回的是一个Boolean类型

  1. #从ymd这一列挑选出2018-03这类型的数据,返回的是一个Boolean类型
  2. condition=df['ymd'].str.startswith('2018-03')
  3. condition

3c718c1f9ee64760918040e48e81c310.png

 

输出在condition条件下的df中的数据

  1. #输出在condition条件下的df中的数据
  2. df[condition].head()

b0fc8b83898942d68b2469d95697b84f.png

4、需要多次str处理的链式操作 

1、先将日期2018-03-31替换成20180331的形式
2、提取月份字符串201803

df['ymd'].str.replace('-','')

f983375ce75849c6a5ab1ef9840f4947.png

问题:直接在Series上面调用方法的话,是否可行?

答:不可行

原因:每次调用函数,都会返回一个新的series
df['ymd'].str.replace('-','').slice(0,6)
'Series' object has no attribute 'slice'---意思就是series不能够直接去调用slice函数,必须经过str调用后才可以使用

  1. #原因:每次调用函数,都会返回一个新的series
  2. df['ymd'].str.replace('-','').slice(0,6)
  3. #'Series' object has no attribute 'slice'---意思就是series不能够直接去调用slice函数,必须经过str调用后才可以使用
df['ymd'].str.replace('-','').str.slice(0,6)

318b18b2ce694e2cbb5fa483c0f95e08.png

slice是切片操作,也可以直接为str[0:6]
 

  1. #slice是切片操作,也可以直接为str[0:6]
  2. df['ymd'].str.replace('-','').str[0:6]

66bee709b5614d9ca94c550ee4e4cc96.png

5、使用正则表达式的处理 

  1. #添加新列
  2. def get_riqi(x):
  3. year,month,day=x['ymd'].split('-')
  4. return f'{year}{month}{day}日'
  5. df['中文日期']=df.apply(get_riqi,axis=1)
  6. df['中文日期']

3b903f14db60481e8087878244412a00.png

new question? -----如何将日期中,年月日三个字去除 

方法1:链式replace

  1. #方法1:链式replace
  2. df['中文日期'].str.replace('年','').str.replace('月','').str.replace('日','')

c54cb02f5e334d43adbe99c0bb9822ed.png

Series.str默认开启了正则表达式模式 

方法2:正则表达式替换
 

  1. #方法2:正则表达式替换
  2. df['中文日期'].str.replace('[年月日]','',regex=True)

1c1d86ed81d54933a81c3e68d88ecb3f.png
 

注:

The default value of regex will change from True to False in a future version.
在Pandas未来的版本中,.str.replace() 的regex的默认值将从True变为False
而当regex=True时,单字符正则表达式不会被视为文本字符串
因为我们是针对price中两个单个字符进行操作,因此设置regex=True 

f722ce8f79024f7497a4d4ee3996b08a.png

十、Pandas的axis参数【详解】--Pandas和Numpy的结合

 0、Pandas的axis参数怎么理解?

. axis=O或者"index":
    ·如果是单行操作,就指的是某一行
    ·如果是聚合操作,指的是跨列cross columns
. axis=1或者"columns":
    -如果是单列操作,就指的是某一列
    ·如果是聚合操作,指的是跨列cross columns

按哪个axis,就是这个axis要动起来(类似被or遍历),其它的axis保持不动

  1. import pandas as pd
  2. import numpy as np
  3. df=pd.DataFrame(
  4. np.arange(12).reshape(3,4),
  5. columns=['A','B','C','D']
  6. )
  7. df

0eb8ed3b0af14846970ccbc159141053.png

 1、单列drop,就是删除一列

代表的就是删除某列

  1. #代表的就是删除某列
  2. df.drop('A',axis=1)

e1cd2770fd58459bbf2a54376a6b7ae9.png

 

2、单行drop,就是删除一行

代表的就是删除某行
 

  1. #代表的就是删除某行
  2. df.drop(1,axis=0)

b730caf780c640eaa93d24a35e922596.png

3、按axis=0/index执行Mean聚合操作

并不是像我们想象的那个样子,输出的是每列的结果!!!

axis=0 or axis=index

  1. # axis=0 or axis=index
  2. df.mean(axis=0)

6f0b9c33b8bb4112bd185bd7692a3b10.png
 

0615ce32ae464f0e8dc803e9301f83c7.png

指定了按那个axis,就是这个axis要动起来(类似被for遍历),其他的axis保持不动 

 

4、按axis=1/colums执行mean聚合操作

并不是像我们想象的那个样子,输出的是每行的结果!!

 axis=1 or axis=colums

  1. # axis=0 or axis=colums
  2. df.mean(axis=1)

b7ac8ed49de343689fee478258b98f7c.png
 

962eb89f899f46c3a47cf67f3aebe055.png 

 指定了按那个axis,就是这个axis要动起来(类似被for遍历),其他的axis保持不动

 

5、举例证明

  1. def get_sum(x):
  2. return x['A']+x['B']+x['C']+x['D']
  3. df['sum']=df.apply(get_sum,axis=1)
  4. df
  5. #跨列相加

60ceddd6ca2f48c8b9545aa298093cb7.png

 

十一、Pandas的索引index所具备的四大性能

 0、Pandas的索引index

Pandas的索引index的用途:

把数据存储于普通的column列也能用于数据查询,那使用index有什么好处?

index的用途总结:

1.更方便的数据查询;

2.使用index可以获得性能提升;

3.自动的数据对齐功能;

4.更多更强大的数据结构支持;

 

1.更方便的数据查询

  1. import pandas as pd
  2. df=pd.read_csv('./datas/ml-latest-small/ratings.csv')
  3. df.head()

0493490eae4a4924bc01ad22a7a47966.png

查询index的数量:df.count()

df.count()

bc8bcd22d960427f98199421fb629491.png
 

drop==False,让索引列还保持在column:意思就是使id这一列继续存在于数据当中

  1. #drop==False,让索引列还保持在column:意思就是使id这一列继续存在于数据当中
  2. df.set_index('userId',inplace=True,drop=False)
  3. df.head()

0b5080e0e09241e9a36fb0bd8b786488.png

df.index

 69a1876aebb544be98b89e6285fab17c.png

第一种:使用index查询的方法---会使查询的代码比较简单
df.loc[500].head() 

  1. #第一种:使用index查询的方法---会使查询的代码比较简单
  2. df.loc[500].head()

78af2c5efe1c43409cb8e8618474fead.png

第二种:使用column的condition查询方法
condition=df['userId']
df.loc[condition==500].head() 

  1. #第二种:使用column的condition查询方法
  2. condition=df['userId']
  3. df.loc[condition==500].head()

a3fca61a7fce409e83609508698e869f.png

 

2.使用index会提升查询性能

如果index是唯一的,Pandas会使用哈希表优化,查询性能为O(1);

如果index不是唯一的,但是有序,Pandas会使用二分查找算法,查询性能为O(logN);

如果index是完全随机的,那么每次查询都要扫描全表,查询性能为O(N);

123bc28678174a62bec1ffde832ec6f0.png

实验1:完全随机的顺序查询 

将数据随机打散

  1. !pip install sklearn
  2. #将数据随机打散
  3. from sklearn.utils import shuffle
  4. df_shuffle=shuffle(df)
  5. df_shuffle.head()

61cc113af3f24d04942d8744adeb3c5a.png

查询我们的索引是不是递增的
df_shuffle.index.is_monotonic_increasing 

  1. #查询我们的索引是不是递增的
  2. df_shuffle.index.is_monotonic_increasing

查询我们的索引是不是递减的
df_shuffle.index.is_monotonic_decreasing

  1. #查询我们的索引是不是递减的
  2. df_shuffle.index.is_monotonic_decreasing

  %timeit 函数是经过大量运算,统计计算出平均运行所用的时间
 计时,查询id==500数据性能
%timeit df_shuffle.loc[500]

  1. # %timeit 函数是经过大量运算,统计计算出平均运行所用的时间
  2. # 计时,查询id==500数据性能
  3. %timeit df_shuffle.loc[500]

32b19a84293a47cbbf3ef6a13d019839.png

实验2:将index排序后查询 

调用sort函数默认为升序操作

  1. #调用sort函数默认为升序操作
  2. df_sorted=df_shuffle.sort_index()
  3. df_sorted.head()
  4. df_sorted.index.is_monotonic_increasing

调用sort函数默认为降序操作 设置为ascending=False为降序操作
 

  1. #调用sort函数默认为降序操作 设置为ascending=False为降序操作
  2. df_sorted2=df_shuffle.sort_index(ascending=False)
  3. df_sorted2.index.is_monotonic_decreasing

判断索引是不是唯一的
df_sorted.index.is_unique

  1. #判断索引是不是唯一的
  2. df_sorted.index.is_unique

如果index不是唯一的,但是有序,Pandas会使用二分查找算法,查询性能为O(logN);
%timeit df_sorted.loc[500]

  1. #如果index不是唯一的,但是有序,Pandas会使用二分查找算法,查询性能为O(logN);
  2. %timeit df_sorted.loc[500]

c1e3cff1c22b458b812f35940df63af2.png

3、使用index能自动对齐数据

包括series和dataframe

index会自动对齐

  1. #index会自动对齐
  2. s1=pd.Series([1,2,3],index=list('abc'))
  3. s1
  1. s2=pd.Series([2,3,4],index=list('bcd'))
  2. s2

当s1+s2中遇到另一方没有找到相同的索引时,会显示NaN,无法进行算术操作时
 

  1. #当s1+s2中遇到另一方没有找到相同的索引时,会显示NaN,无法进行算术操作时
  2. s1+s2

96c0a90d09704092a1043f5caad51c7a.png
 

4.使用index更多更强大的数据结构支持

很多强大的索引数据结构

Categoricallndex,基于分类数据的Index,提升性能;

Multilndex,多维索引,用于groupby多维聚合后结果等;

Datetimelndex,时间类型索引,强大的日期和时间的方法支持;

 

十二、Pandas的Merge语法(内含设置行名方法)

1、 Pandas怎样实现DataFrame的Merge

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

merge的语法:

pd.merge(left,right, how='nner , on=None,left_on=None, right_on=None,lef_index=False,right_index=False,sort=True, sufises=(‘_X’ ,“_Y” ), opy=Tue,indicator=False, validate=None)

 

left,right:要merge的dataframe或者有name的Series.
how: join类型,'left', 'right', 'outer', 'inner'
on: join的key,left和right都需要有这个key. 
left_on: left的df或者series的key
right_on: right的df或者seires的key
left_index,right_index:使用index而不是普通的column做join
suffixes:两个元素的后缀,如果列有重名,自动添加后缀,默认是('_X','_y')

本次讲解提纲:
    1.电影数据集的join实例
    2.理解merge时一对一、一对多、多对多的数量对齐关系
    3.理解left join、right join、inner join、outer join的区别
    4.如果出现非Key的字段重名怎么办

  1. import pandas as pd
  2. df_ratings=pd.read_csv(
  3. './datas/movielens-1m/ratings.dat',
  4. sep="::",#设置其分隔服为::
  5. engine='python',#因为pandas语法中sep为两个字符的时候,系统默认其为正则表达式,但是分隔符就是::不是正则表达式,所以加engine=python
  6. names='UserID::MovieID::Rating::Timestamp'.split('::')
  7. )
  8. df_ratings.head()

5e93e4fb9597460a82be492855ad5f65.png

  1. df_users=pd.read_csv(
  2. './datas/movielens-1m/users.dat',
  3. sep="::",
  4. engine='python',
  5. names='UserID::Gender::Age::Occupation::Zip-code'.split('::')
  6. )
  7. df_users.head()

a31a0a6c5c544d5da0a5ca5a7f20f74f.png

 

  1. df_movies=pd.read_csv(
  2. './datas/movielens-1m/movies.dat',
  3. sep='::',
  4. engine='python',
  5. names='MovieID::Tile::Genres'.split("::")
  6. )
  7. df_movies.head()

09c894360a8a4c40ac010768306fdcf3.png

  1. df_ratings_users=pd.merge(
  2. df_ratings,df_users,on='UserID',how='inner'
  3. )
  4. df_ratings_users.head()

140bd8157c564075960170833d9d3a37.png

  1. df_ratings_users_movies=pd.merge(
  2. df_ratings_users,df_movies,left_on='MovieID',right_on='MovieID',how='inner'
  3. )
  4. df_ratings_users_movies.head()

df93b393feaf4c9ca7ccb674be094bfc.png

2、理解merge时数量的对齐关系以下关系要正确理解:

. one-to-one:—对一关系,关联的key都是唯一的

.比如(学号,姓名) merge (学号,年龄)

-结果条数为:1*1

. one-to-many:一对多关系,左边唯一key,右边不唯一key

-比如(学号,姓名) merge(学号,[语文成绩、数学成绩、英语成绩])

结果条数为:1*N

. many-to-many : [多对多关系,左边右边都不是唯一的

·比如(学号,[语文成绩、数学成绩、英语成绩])merge (学号,[篮球、足球、乒乓球)

-结果条数为:M*N

2.1 one-to-one 一对一关系的merge

df358241e1ba41a1a235bc6b26458bc0.png

  1. left=pd.DataFrame({
  2. 'sno':[11,12,13,14],
  3. 'name':['name_a','name_b','name_c','name_d']
  4. }
  5. )
  6. left

 8d850fbf79944689a60eae462a5e6b70.png

  1. right=pd.DataFrame({
  2. 'sno':[11,12,13,14],
  3. 'age':['21','22','23','24']
  4. })
  5. right

 cb81d1fe932240fcb48ba5e709b54be0.png

  1. #一对一关系中:结果有四条
  2. pd.merge(left,right,on='sno')

8ac227c47ee944e3818426209c6d0736.png

2.2 one-to-many一对多关系的

merge注意:数据会被制

9e8145a1261e43198f50bed67a169702.png

  1. left=pd.DataFrame({
  2. 'sno':[11,12,13,14],
  3. 'name':['name_a','name_b','name_c','name_d']
  4. }
  5. )
  6. left

 c795b617215b49de81a4d446e8c0563f.png

 b91ed60f6c5d4ba8a7bc963cdffef394.png

  1. right=pd.DataFrame({
  2. 'sno':[11,11,11,12,12,13],
  3. 'grade':['英语:21','语文:22','数学:23','英语:24',"语文:11","数学:55"]
  4. })
  5. right

0d2f1a0c5e4b4fbd9ab9840ca93af2e6.png

 

  1. #一对多的关系对name名字进行了复制
  2. pd.merge(left,right,on='sno')

0dd6b0a337a44bcdae5fe464b7806730.png

 

2.3 many-to-many多对多关系的merge

注意:结果数量会出现乘法

469338e5856041e791d144983e70f229.png

 

  1. left=pd.DataFrame({
  2. 'sno':[11,11,12,12,12],
  3. '爱好':['篮球','羽毛球','乒乓球','篮球','足球']
  4. }
  5. )
  6. left
  1. right=pd.DataFrame({
  2. 'sno':[11,11,11,12,12,13],
  3. 'grade':['英语:21','语文:22','数学:23','英语:24',"语文:11","数学:55"]
  4. })
  5. right

5202cdddf5f043b39f3e9739b3c1b83e.png

pd.merge(left,right,on='sno')

aa9288f82b95492398580dca84180292.png

 3、理解left join、right join、inner join、outer join的区别

888502f89f83450e9fbf19974f35d77c.png

  1. left=pd.DataFrame({
  2. 'key':['ko','k1','k2','k3'],
  3. 'A':['A0','A1','A2','A3'],
  4. 'B':['B0','B1','B2','B3']
  5. })
  6. right=pd.DataFrame({
  7. 'key':['k0','k1','k2','k3'],
  8. 'C':['C0','C1','C2','C3'],
  9. 'D':['D0','D1','D2','D3']
  10. })
  11. left

 720dc21c55474fa089d819c144921327.png

3.1 inner join,默认

左边和右边的key都有,才会出现在结果里

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

22a8621801ed4eed8a01671ebc79e0f6.png

3.2 left join

左边的都会出现在结果里,右边的如果无法匹配则为Null

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

12cac8202ebc4f4683c71008a47bcd70.png

3.3 right join

右边的都会出现在结果里,左边的如果无法匹配则为Nul

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

8bae8369168a4ab889a56fb795816426.png

3.4 outer join

左边、右边的都会出现在结果里,如果无法匹配则为Null

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

9d9601f8a697425f9520c312265680c0.png

 4、如果出现非Key的字段重名怎么办

  1. left=pd.DataFrame({
  2. 'key':['K0','k1','k2','k3'],
  3. 'A':['A0','A1','A2','A3'],
  4. 'B':['B0','B1','B2','B3']
  5. })
  6. right=pd.DataFrame({
  7. 'key':['K0','K1','K4','K5'],
  8. 'A':['A10','A11','A12','A13'],
  9. 'D':['D0','D1','D4','D5']
  10. })
  11. left

b85e2208dfa3415abfaa6c0ff46db75d.png

 

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

suffixes=('name1','name2')可以直接设置重名函数的函数名
pd.merge(left,right,on='key',suffixes=('_left','_right'))

  1. #suffixes=('name1','name2')可以直接设置重名函数的函数名
  2. pd.merge(left,right,on='key',suffixes=('_left','_right'))

ab8db2d9374541e6923572762aaea467.png

十三、Pandas 的Concat合并【实现Concat合并】

0、 Pandas实现数据的合并concat

使用场景:

批量合并相同格式的Excel、给DataFrame添加行、给DataFrame添加列

一句话说明concat语法:

。使用某种合并方式(inner/outer)

·沿着某个轴向(axis=0/1)

·把多个Pandas对象(DataFrame/Series)合并成一个。

concat语法: pandas.concat(objs, axis=0, join='outer', ignore_index=False)

. objs: 一个列表,内容可以是DataFrame或者Series,可以混合

. axis: 默认是0代表按行合并,如果等于1代表按列合并

. join:合并的时候索引的对齐方式,默认是outer join,也可以是inner join.

ignore_index:是否忽略掉原来的数据索引

append语法: DataFrame.append(other, ignore_index=False)

append只有按行合并,没有按列合并,相当于concat按行的简写形式.

other:单个dataframe、series、dict,或者列表

ignore_index:是否忽略掉原来的数据索引

  1. import pandas as pd
  2. import warnings
  3. warnings.filterwarnings('ignore')

1、使用pandas.concat合并数据

  1. df1=pd.DataFrame({
  2. 'A':['A0','A1','A2','A3'],
  3. 'B':['B0','B1','B2','B3'],
  4. 'C':['C0','C1','C2','C3'],
  5. 'D':['D0','D1','D2','D3'],
  6. 'E':['E0','E1','E2','E3']
  7. })
  8. df2=pd.DataFrame({
  9. 'A':['A4','A5','A6','A7'],
  10. 'B':['B4','B5','B6','B7'],
  11. 'C':['C4','C5','C6','C7'],
  12. 'D':['D4','D5','D6','D7'],
  13. 'F':['F4','F5','F6','F7']
  14. })
  15. df1

9f6d9601e2d44cc8b249e1a711225ef6.png

df2

 1、默认的concat,参数为axis=0、 join=outer、ignore_index=False

因为默认axis=0,即第二个df2的值默认放在第一个df1内容的下面,即所谓的行合并
pd.concat([df1,df2])

  1. #因为默认axis=0,即第二个df2的值默认放在第一个df1内容的下面,即所谓的行合并
  2. pd.concat([df1,df2])

618ce7e3ff154c61859a7a3870654005.png

2、使用ignore_index=True可以忽略原来的索引 

忽略原来的缩影的列,从0,1,2,3........
pd.concat([df1,df2],ignore_index=True)

1730b164109647bfaf2264bed63611fb.png

3、使用join=inner过滤掉不匹配的列 

意思就是只要任意一组没有就进行过滤
pd.concat([df1,df2],ignore_index=True,join='inner')

  1. #意思就是只要任意一组没有就进行过滤
  2. pd.concat([df1,df2],ignore_index=True,join='inner')

9234065c4f444b56b5aa3083960b5d19.png

4、使用axis=1相当于添加新列 

df1

351667037f004aa192eb625bfc05de8b.png

A:添加一列Series 

  1. s1=pd.Series(list(range(4)),name='F')
  2. s1
  3. pd.concat([df1,s1],axis=1)

081ba07b598648c3b5e8d0b09e1ee397.png

B:添加多列Series 

  1. s2=df1.apply(lambda x:x["A"]+'_11',axis=1)
  2. s2
  1. s2.name='G'
  2. pd.concat([df1,s1,s2],axis=1)
  1. #列表中可以只有Series
  2. pd.concat([s1,s2],axis=1)
  1. #列表也可以是混合顺序的
  2. pd.concat([s1,df1,s2],axis=1)

48f4a142fd0c434ab68474f052638a57.png

4e1fc281f2034917a4aa4825a470cfcb.png

二、使用DataFrame.append按行进行合并数据 

  1. df1=pd.DataFrame([[1,2],[3,4]],columns=list('AB'))
  2. df1
  1. df2=pd.DataFrame([[5,6],[7,8]],columns=list('AB'))
  2. df2

9d28dccfa53d4cdfbfa3f4a05c09e212.png

 1、给一个dataframe添加另一个dataframe

df1.append(df2)

be0396e6e2fc4e26a75a31fae8f01334.png

 

2、忽略原来的索引ignore_index=True

df1.append(df2,ignore_index=True)

27c106ea3c124daa94ce377979546240.png

 

3、可以一行行的给DataFrame添加数据

  1. #一个空的df
  2. df=pd.DataFrame(columns=['A'])
  3. df

d14f7bacefd94cb290321c5f8328288c.png

A:低新能版本

  1. for i in range(5):
  2. #利用这种循环,每次都在复制
  3. df=df.append({'A':i},ignore_index=True)
  4. df

68ff332358144c26988b829eb6a250fe.png

 

B:高新能版本

  1. #第一个入参的是列表,避免了多次的复制,直接往里面添加就可以了
  2. pd.concat(
  3. [pd.DataFrame([i],columns=['A']) for i in range(5)],
  4. ignore_index=True
  5. )

a2d0a4606ef34b53ae26441e15242ae8.png

十四、Pandas批量拆分与合并Excel文件

0、 Pandas批量拆分Excel与合并Excel

实例演示:

1.将一个大Excel等份拆成多个Excel

2.将多个小Excel合并成一个大Excel并标记来源

  1. #本节课的数据目录work_dir
  2. work_dir='./course_datas/c15_excel_split_merge'
  3. #work_dir下面的splits目录,来放置拆分后的小文件
  4. splits_dir=f'{work_dir}/splits'
  5. import os
  6. #如果splits_dir目录不存在就创建一个小目录
  7. if not os.path.exists(splits_dir):
  8. os.mkdir(splits_dir)

1、读取源Excel到Pandas

  1. import pandas as pd
  2. df_source=pd.read_excel(f'{work_dir}/crazyant_blog_articles_source.xlsx')
  3. df_source.head()

40dee1841eb140f5bb75a7ed35c7da1c.png

  1. df_source.index
  2. df_source.shape
  3. total_row_count=df_source.shape[0]
  4. total_row_count

7302cbb5aa49446cab0112c5a58a4a6d.png

 

一、将一个大Excel等份拆成多个Excel

1.使用df.iloc方法,将一个人的dataframe,拆分成多个小dataframe

2.将使用dataframe.to_excel保存每个小Excel

1、计算拆分后的每个excel的行数

  1. #将一个大的EXCEL文件拆分给这几个人
  2. user_name=['xiaohu','xiaoshuai','xiaolan','xiaofan','xiaok','xiaom']
  1. #每个人的任务数目
  2. splits_size=total_row_count//len(user_name)
  3. #判断每个人分配的任务数是否为整数,若不为整数则+1
  4. if total_row_count % len(user_name) !=0:
  5. splits_size+=1
  6. splits_size

03c98955dca34a7b9bc94fda2a28e106.png

2、拆分成多个dataframe

  1. #将拆出来的小的dataframe存在df_sub[]当中
  2. df_subs=[]
  3. for index,user_name in enumerate(user_name):
  4. #iloc的开始索引,从0开始进行索引
  5. begin=index*splits_size
  6. #iloc的结束索引
  7. end=begin+splits_size
  8. #实现df按照iloc拆分
  9. df_sub=df_source.iloc[begin:end]
  10. #将每个子df存入列表
  11. df_subs.append((index,user_name,df_sub))

3、将每个datafame存入excel

  1. for index,user_name,df_sub in df_subs:
  2. file_name=f'{splits_dir}/crazyant_blog_articles_{index}_{user_name}.xlsx'
  3. df_sub.to_excel(file_name,index=False)

二、合并多个小Excel到一个大Excel

1.遍历文件夹,得到要合并的Excel文件列表

2.分别读取到dataframe,给每个df添加—列用于标记来源

3.使用pd.concat进行df批量合并

4.将合并后的dataframe输出到excel

1、遍历文件夹,得到要合并的Excel名称列表

  1. import os
  2. excel_names=[]
  3. for excel_name in os.listdir(splits_dir):
  4. excel_names.append(excel_name)
  5. excel_names
  6. #os.listdir() 方法用于返回指定的文件夹包含的文件或文件夹的名字的列表。

95b7c9d7d8724ddeb0ed6b055326941c.png

2、分别读取到dataframe 

  1. df_list=[]
  2. for excel_name in excel_names:
  3. #将每个excel读取到df当中
  4. excel_path=f'{splits_dir}/{excel_name}'
  5. df_split=pd.read_excel(excel_path)
  6. #得到username
  7. username=excel_name.replace('crazyant_blog_articles_','').replace('.xlsx','')[2:]
  8. print(excel_name,username)
  9. #给每个df添加1列,即用户名字
  10. df_split['username']=username
  11. df_list.append(df_split)

6b94d08b107a4545b3d7ad0b661d4b0e.png

3、使用pd.concat进行合并 

  1. df_merged=pd.concat(df_list)
  2. df_merged.shape
  3. df_merged.head()

e51a62b02326479a92daada4553bedc9.png

df_merged['username'].value_counts()

 a16bfb7176574316892e8c710d432af1.png

4、将合并后的dataframe输出到excel中 

df_merged.to_excel(f'{work_dir}/crazyant_blog_articles_merged.xlsx',index=False)

 

十五、Pandas怎样实现groupby分组统计

0、 Pandas怎样实现groupby分组统计

类似SQL: select city,max(temperature) from city_weather group by city;

groupby:先对数据分组,然后在每个分组上应用聚合函数、转换函数

本次演示:

一、分组使用聚合函数做数据统计

二、遍历groupby的结果理解执行流程

三、实例分组探索天气数据

  1. import pandas as pd
  2. import numpy as np
  3. #在jupyter notebook中展示matplot图表
  4. %matplotlib inline
  1. df=pd.DataFrame({
  2. 'A':['foo','bar','foo','bar','foo','bar','foo','foo'],
  3. 'B':['one','one','two','three','one','one','two','three'],
  4. 'C':np.random.randn(8),
  5. 'D':np.random.randn(8)
  6. })
  7. df

be3959c242864a46b0cfbe42bfb3b2c1.png

1、分组使用聚合函数做数据统计

1、单个列groupby,查询所有数据列的统计

  1. P=df.groupby('A').sum()
  2. #聚合操作后P仍然是一个Dataframe
  3. P

8c92c1edf5d7465eb48d7a4ead1ec83d.png

df.groupby('name').sum()

Ps: 1、将name列的不同名称作为索引

  1. 2、忽略df中不是数字列的一列
  2. 3、对是数字列的一列进行累加
  3. 4、统计在name不同名称下的,其他值的和

2、多个列groupby,查询所有数据列的统计

df.groupby(['A','B']).mean()

baafc3a9808a454097d3ebb0d59223d9.png

 

1、选取A、B两列的不同名称作为索引---在这里因为A列的bar没有B列中的two所以没有

2、对数字列进行求取平均值

3、统计在不同名下的平均值

4、将A、B变成二级索引

  1. #设置as_index=False,取消A、B作为二级索引
  2. df.groupby(['A','B'],as_index=False).mean()

c3808ed3196b4daca9e80adf8b432f78.png

3、同时查看多种数据统计 

df.groupby('A').agg([np.sum,np.mean,np.std])

00b99851bc5245b8b0c2fb825e33f843.png

1、将name列的不同名称作为索引

  1. 2、忽略df中不是数字列的一列
  2. 3、对是数字列的一列进行操作
  3. 4、统计在name不同名称下的,其他值的和

列变成了多级索引

4、查看单列的结果数据统计

  1. #方法1:预过滤,性能更好
  2. df.groupby('A')['C'].agg([np.sum,np.mean,np.std])

 45ffc204b2d4463684fba020714698e1.png

  1. #方法2:
  2. df.groupby('A').agg([np.sum,np.mean,np.std])['C']

9ed4e1f8c97a4faab2e57ded9d9c2499.png

5、不同列使用不同的聚合函数 

  1. df.groupby('A').agg({
  2. 'C':np.sum,
  3. 'D':np.mean
  4. })

 d642272fa91f47b98b570c3798f2551e.png

二、遍历groupby的结果理解执行流程

for循环可以直接遍历每个group

1、遍历单个列聚合的分组

  1. g=df.groupby('A')
  2. g
  3. #相当于对A索引的不同值的列进行一个汇总,使数据看起来更加的清晰
  1. for name,group in g:
  2. print(name)
  3. print(group)
  4. print( )

c407b3c7220749a0a376d73c218c3f02.png

可以获取单个分组的数据 

g.get_group('bar')

00db952d8a7742e5affb1d10c886d9db.png

2、遍历多个列聚合的分组 

  1. g=df.groupby(['A','B'])
  2. for name,group in g:
  3. print(name)
  4. print(group)
  5. print( )
  6. #name 是一个2个元素的元组,代表不同的列

de6d8350e8604c26b3b1019520e4ccaf.png

可以直接查询group后的某几列,生成Series或者子DataFrame 

  1. g['C']
  2. for name,group in g:
  3. print(name)
  4. print(group)
  5. print( )

3dd2900bf0a145c29307fd770b84fc0a.png

本质:所有的聚合统计,都是在dataframe和series上进行的

三、实例分组探索天气数据

  1. fpath='./datas/beijing_tianqi/beijing_tianqi_2018.csv'
  2. df=pd.read_csv(fpath)
  3. df

 bd75956e0aec441eabb2353302a3b689.png

  1. #替换掉温度后缀℃
  2. df.loc[:,'bWendu']=df['bWendu'].str.replace('℃','')
  3. df.loc[:,'yWendu']=df['yWendu'].str.replace('℃','')
  4. df

797e501e19804a8a852921e65159bbbc.png

  1. df2=df.drop(labels=['bWendu','yWendu'], axis=0, inplace=False)
  2. df2

e12c739e2ba244dcb8e12fdced2ce271.png

  1. df2.loc[:,'bWendu']=df2['bWendu'].astype('int32')
  2. df2.loc[:,'yWendu']=df2['yWendu'].astype('int32')
  3. df2.head()

d6e093a6bd064dd2876a3e203f48e2db.png

  1. #新增一列为月份
  2. df['month']=df['ymd'].str[:7]
  3. df.head()

 603a24d55f9149baaaba4d1632ebd302.png

 1、查看每个月的最高温度

  1. data=df.groupby('month')['bWendu'].max()
  2. data

44a77da525304077bae06d56d3ebdac9.png

  1. type(data)
  2. data=data.astype(float)
  3. data.plot()

c358e4d554ac49e381f43c6d4d83723d.png

 2、查看每个月的最高温度、最低温度、平均空气质量指数

  1. df.head()
  2. group_data=df.groupby('month').agg({'bWendu':np.max,'yWendu':np.min,'aqi':np.mean})
  3. group_data

8f1c200883eb4defb53968906f896118.png

91b2e8553930455695d83faaa2af46eb.png

group_data.plot()

 8aa174433fc04be8a5c5ea9dfe0d47fc.png

 

十六、Pandas的分层索引MultiIndex怎么用?

0、 Pandas的分层索引Multilndex

1为什么要学习分层索引Multilndex?

1、分层索引:在一个轴向上拥有多个索引层级,可以表达更高维度数据的形式;

2、方便的进行数据筛选,如果有序则性能更好;

3、groupby等操作的结果,如果是多KEY,结果是分层索引,需要会使用。

4、一般不需要自己创建分层索引(Multilndex有构造函数但一般不用)

演示数据:百度、阿里巴巴、爱奇艺、京东四家公司的10天股票数据数据来自:英为财经

—、Series的分层索引Multilndex

二、Series有多层索引怎样筛选数据?

三、DataFrame的多层索引Multilndex

四、DataFrame有多层索引怎样筛选数据?

  1. import pandas as pd
  2. %matplotlib inline
  3. stocks=pd.read_excel('./datas/stocks/互联网公司股票.xlsx')
  4. stocks.shape
stocks

c3498eecb3764d98b65de9b2043025f4.png

 

  1. stocks['公司'].unique()
  2. stocks.index
  3. #计算每个公司收盘的平均值
  4. stocks.groupby('公司')['收盘'].mean()

7a137812d7824162a1e4a7afa659cee2.png

1、Series的分层索引MultiIndex 

  1. ser=stocks.groupby(['公司','日期'])['收盘'].mean()
  2. ser
ser.index
  1. # unstack把二级索引变成列
  2. ser.unstack()
  3. ser
  1. #全部变成一维的普通索引模式
  2. ser.reset_index()

76c0387e929549d79de717e9e7e791c2.png

 ba864af5686d4164bf04f854ef3941d0.png

5a5ef5f84098469eb7c1140a0e531035.png 2、Series有多层索引Multilndex怎样筛选数据?

 

  1. ser
  2. ser.loc['BIDU']
  3. # 多层索引,可以用元组的形式进行筛选
  4. ser.loc[('BIDU','2019-10-02')]

f85d891c11624f33bac198e2ddeaca8f.png

  1. #求所有公司中指定月份的收盘价
  2. ser.loc[:,'2019-10-02']

6a7747ba665a43d8af9006895dbd6b20.png

 3、DataFrame的多层索引Multilndex

  1. stocks.head()
  2. stocks.set_index(['公司','日期'],inplace=True)
  3. stocks

bdeab30dd06242fd9657297530a54707.png

  1. stocks.index
  2. #自动根据索引进行排序,默认为升序排列
  3. stocks.sort_index(inplace=True)
  4. stocks

ae888f53f12c46bab8db78aeb89ed30e.png

 ad92d53f2ae7476abaa0dab95f49dd58.png

 

4、DataFrame有多层索引Multilndex怎样筛选数据?

【重要知识】在选择数据时:

。元组(key1.key2)代表筛选多层索引,其中key1是索引第一级,key2是第二级,比如key1=JD, key2=2019-10-02

·列表[key1,key2]代表同一层的多个KEY,其中key1和key2是并列的同级索引,比如key1=JD, key2=BIDU

stocks.loc['BIDU']

821dfe667dcd4d358f78c7831bbf9768.png

  1. # 'BIDU'是一级索引 '2019-10-02'是二级索引
  2. stocks.loc[('BIDU','2019-10-02'),:]

 5e2d0bbe6f4e426f86ec687a8095006c.png

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

f72b1bde7c1940ba8e2673df3ad8f86a.png

  1. #设置日期的同一级索引的格式
  2. stocks.loc[('BIDU',['2019-10-03','2019-10-02']),'收盘']

d370cdc2c698433db106fcbdff4f4f31.png

  1. #slice(None)代表筛选中一索引的所有内容---在这里的意思就是筛选一级索引‘公司’的所有内容
  2. stocks.loc[(slice(None),['2019-10-03','2019-10-02']),:]

774c7b0576ac42268e48eb965c87ce8c.png

 

  1. #将多重索引全部重置,转换为一维索引
  2. stocks.reset_index()

41bc89889ce04bff9da89e6787086439.png

十七、Pandas的数据转换函数--map、apply、applymap

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

数据转换函数对比: map、apply、applymap

1.map用于Series值的转换

实例:将股票代码英文转换成中文名字

Series.map(dict) or Series.map(function)均可

  1. import pandas as pd
  2. stocks=pd.read_excel('./datas/stocks/互联网公司股票.xlsx')
  3. stocks.head()

6098a53104cb48b2b1da6d13d1d4a996.png

stocks['公司'].unique()
  1. #公司股票代码到中文的映射,注意这里要小写
  2. dict_company_names={
  3. 'bidu':'百度',
  4. 'baba':'阿里巴巴',
  5. 'iq':'爱奇艺',
  6. 'jd':'京东'
  7. }

5ed6eeacb28a4ebc93dfc3b21231d7e4.png

方法1:Series.map(dict) ----在map函数中传进去一个字典只用于Series 

  1. # stocks['公司'].str.lower()---将公司中的所有字母转换为小写字母
  2. # .map(dict_company_names)--把公司中所有对应的列转换为其对应的中文字母
  3. stocks['公司中文1']=stocks['公司'].str.lower().map(dict_company_names)
  4. stocks.head()

8a3ed167b50341e68c57d2e3e97953f4.png

方法2:Series.map(function) ----在map函数中传进去一个自定义函数只用于Series

function的参数是Series的每个元素的值

  1. stocks['公司中文2']=stocks['公司'].map(lambda x:dict_company_names[x.lower()])
  2. stocks.head()

b560541c47e241eea708f1656532a7b1.png

2.apply用于Series和DataFrame的转换---既可以用于Series也可以用于DataFrame

Series.apply(function),函数的参数是每个值.

DataFrame.apply(function),函数的参数是Series

Series.apply(function)

function的参数是Series的每个值

  1. stocks['公司中文3']=stocks['公司'].apply(
  2. lambda x:dict_company_names[x.lower()]
  3. )
  4. stocks.head()

c2c036e0a5144b47bb77d0054dac2f0e.png

DataFrame.apply(function)

function的参数是对应轴的Series

  1. stocks['公司中文4']=stocks.apply(
  2. lambda x:dict_company_names[x['公司'].lower()],
  3. axis=1
  4. )
  5. stocks.head()

 36356aea4b384370b70c3e493c328f63.png

 

注意这个代码:

  1. 1、apply是在stocks这个DataFrame上调用;
  2. 2lambda x的x是一个Series,因为指定了axis=1所以Seires的key是列名,可以用x[公司"]获取

3.applymap用于DataFrame所有值的转换

  1. sub_df=stocks[['收盘','开盘','高','低','交易量']]
  2. sub_df.head()

2ec826eab60f4ff2aab6e78d43b3df73.png

  1. #将这些数字取整数,应用于所有元素
  2. sub_df.applymap(lambda x:int(x))

 23239aaf8e2f4851b86526033eef6664.png

  1. #直接修改原df的这几列
  2. stocks.loc[:,['收盘','开盘','高','低','交易量']]=sub_df.applymap(lambda x:int(x))
  3. stocks.head()

257a8cbdeb5e40558b3aa5633d7a6fa7.png

十八、Pandas如何对每个分组应用apply函数

0、 Pandas怎样对每个分组应用apply函数?

知识:Pandas的GroupBy遵从split、apply.combine模式

71759e81209045579db47b0ea3c733f9.png

这里的split指的是pandas的groupby,我们自己实现apply函数,apply返回的结果由pandas进行combine得到结果

GroupBy.apply(function)

. function的第一个参数是dataframe

. function的返回结果,可是dataframe、series、单个值,甚至和输入dataframe完全没关系

本次内容:

1.怎样对数值列按分组的归—化?

2.怎样取每个分组的TOPN数据?

实例1:怎样对数值列按分组的归一化?

将不同范围的数值列进行归一化,映射到[0,1]区间:

·更容易做数据横向对比,比如价格字段是几百到几千,增幅字段是0到100

·机器学习模型学的更快性能更好

归一化的公式:

8f6724b1db824e5082d3712712b3014a.png

演示:用户对电影评分的归一化

每个用户的评分不同,有的乐观派评分高,有的悲观派评分低,按用户做归—化
  1. import pandas as pd
  2. ratings=pd.read_csv(
  3. './datas/movielens-1m/ratings.dat',
  4. sep='::',
  5. engine='python',
  6. names='UserID::MovieID::Rating::Timestamp'.split('::')
  7. )
  8. ratings.head()

 eb233bfead7249a287ec2c04ea6d25b6.png

  1. #实现按照用户ID分组,然后对其中一列进行归一化
  2. def ratings_room(df):
  3. '''
  4. 每个用户分组的dataframe
  5. '''
  6. min_value=df['Rating'].min()
  7. max_value=df['Rating'].max()
  8. df['Rating_rooms']=df['Rating'].apply(
  9. lambda x:(x-min_value)/(max_value-min_value)
  10. )
  11. return df
  12. ratings=ratings.groupby('UserID').apply(ratings_room)
  13. ratings.head()

97adf11b925740d7b878c04770729b67.png

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

510d3a6a58054332a2d2193e92c6eb67.png

看到UserID==1这个用户,Rating==3是他的最低分,是个乐观派,我们归一化到0分

实例2:怎样取每个分组的TOPN数据?

获取2018年每个月温度最高的2天数据

  1. df=pd.read_csv(
  2. './datas/beijing_tianqi/beijing_tianqi_2018.csv'
  3. )
  4. df.loc[:,'bWendu']=df['bWendu'].str.replace('℃','').astype('int32')
  5. df.loc[:,'yWendu']=df['yWendu'].str.replace('℃','').astype('int32')
  6. #创建一个新的列为月份列
  7. df['month']=df['ymd'].str[:7]
  8. df

a4f17b50116142039c95fcc0e09dfe17.png

  1. def getWenduTopn(df,topn):
  2. '''
  3. 这里的df,是每个月份分组的group的df
  4. '''
  5. df2=df.sort_values(by='bWendu')[['ymd','bWendu']][-topn:]
  6. return df2
  7. df.groupby('month').apply(getWenduTopn,topn=2).head()

c5c9cb8a3b544f6696d5304697130e0f.png

十九、Pandas使用stack和pivot实现数据透视

 0、Pandas的stack和pivot实现数据透视

将列式数据变成二维交叉形式,便于分析,叫做重塑或透视

4aad53c97cf74d12ac89b0bf86d6af40.png

1.经过统计得到多维度指标数据

2.使用unstack实现数据二维透视

3.使用pivot简化透视

4.stack、unstack、pivot的语法

1.经过统计得到多维度指标数据

非常场景的统计场景,指定多个维度,计算聚合后的指标

实例:统计得到"电影评分数据集”,每个月份的每个分数被评分多少次:(月份、分数1~5、次数)

  1. import pandas as pd
  2. import numpy as np
  3. %matplotlib inline
  1. df=pd.read_csv(
  2. './datas/movielens-1m/ratings.dat',
  3. sep='::',
  4. engine='python',
  5. names='UserID::MovieID::Rating::Timestamp'.split('::')
  6. )
  7. df.head()

afceacf02c0e403ebcfdaf86db4e58c4.png

  1. df['pdata']=pd.to_datetime(df['Timestamp'],unit='s')
  2. df.head()

 db7d76cb36de47979bcc7590e8bb8cfe.png

 

df.dtypes
  1. #实现数据统计
  2. df_group=df.groupby([df['pdata'].dt.month,'Rating'])['UserID'].agg(pv=np.sum)
  3. df_group.head()

b7327da6432e4720bc0d2eba61c42001.png

 

对于这样的格式数据,查看按月份,不同评分的次数趋势,是没法实现的

需要将数据变换成每个评分是一列才可以实现

2.使用unstack实现数据二维透视

目的:想要画图对比按照月份的不同评分的数量趋势

  1. df_stack=df_group.unstack()
  2. df_stack

1cc8d909f6a0437f996baf5b553885dc.png

 

df_stack.plot()

d7cfacb00146415f9d022970548d057b.png

 

  1. #unstack和stack是互逆操作
  2. df_stack.stack().head()

acb32051e9cf46c889947c5bbac2ff84.png

 3、使用pivot简化透视

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

1d43f21df9ac45a69e891a99188844eb.png

  1. #因为是二维的---pdata代表x轴,Rating代表y轴,pv代表数据
  2. df_pivot=df_reset.pivot('pdata','Rating','pv')
  3. df_pivot.head()

 af7814b0264144a2a8ae722a5c74aa50.png

df_pivot.plot()

 b13ed55619ec4af5afc171f6907756d8.png

pivot方法相当于对df使用set_index的创建分层索引,然后调用unstack

4.stack、unstack、pivot的语法

stack: DataFrame.stack(level=-1, dropna=True),将column变成index,类似把横放的书籍变成竖放

level=-1代表多层索引的最内层,可以通过==0、1、2指定多层索引的对应层

 2dd53b9317de45899187ebb0279f3409.png

 

unstack: DataFrame.unstack(level=-1, fill_value=None),将index变成column,类似把竖放的书籍变成横放

b2d3d1eedfa84906bc8a6e532931e917.png

pivot: DataFrame.pivot(index=None , columns=None, values=None),指定index、columns、values实现二维透视 

61984caa568e4a8db87492d3c8aa35ed.png

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/75042
推荐阅读
相关标签
  

闽ICP备14008679号