官方文档:https://pandas.pydata.org/
axis=0,表示纵向,行操作
axis=1,表示横向,列操作
在生产环境中,绝大多数数据都存储于数据库中。pandas提供了读取与存储关系型数据库数据的函数与方法。除了pandas库以外,还需要使用SQLAlchemy库建立对应的数据库连接。SQLAlchemy配合相应数据库的Python连接工具(如:MySQL需要pymysql库,Oracle需要cx_engine库),使用create_engine函数,建立一个数据库连接。pandas支持MySQL、postgresql、Oracle、SqlServer和SQLite等主流数据库。
以MySQL为例:
pandas读取MySQL有3个函数,read_sql、read_sql_table、read_sql_query.
import pandas as pd
pd.read_sql(
sql,
con,
index_col=None,
coerce_float=True,
params=None,
parse_dates=None,
columns=None,
chunksize=None,
)
read_sql_query(
sql,
con,
index_col=None,
coerce_float=True,
params=None,
parse_dates=None,
chunksize=None,
)
read_sql_table(
table_name,
con,
schema=None,
index_col=None,
coerce_float=True,
parse_dates=None,
columns=None,
chunksize=None,
)
SQLAlchemy连接MySQL数据库的代码:
from sqlalchemy import create_engine
#用户名为root,密码为1234
#地址为127.0.0.1,数据库名称为testdb,编码为utf-8
#数据库产品名+连接工具名://用户名:密码@数据库IP地址:数据库端口号/数据库名称?charset=数据库数据编码
engine = create_engine('mysql+pymysql://root:[email protected]:3306/testdb?charset=utf-8')
重要参数说明:
参数名称 | 说明 |
---|---|
sql/table_name | 接收string。表示读取的数据的表名或者sql语句 |
con | 接收数据库连接。表示数据库链接信息 |
index_col | 表示设定的列作为列名,如果是一个数列,则是多重索引 |
coerce_float | 接收boolean。将数据库中的decimal类型转为pandas中的float64类型数据 |
columns | 接收list。表示读取数据的列名 |
使用函数读取数据库数据:
formlist = pd.read_sql_query('show tables',con=engine)
detail1 = pd.read_sql_table('table_name',con=engine)
detail2 = pd.read_sql('se;ect * from meal_order_detail2',con=engine)
将DataFrame写入数据库中,也要依赖SQLAlchemy库的create_engine函数创建数据库连接。数据库存储只有一个方法:to_sql()
,其用法与常用参数
DateFrame.to_sql(
name,
con,
schema=None,
if_exists="fail",
index=True,
index_label=None,
chunksize=None,
dtype=None,
method=None,
)
参数名称 | 说明 |
---|---|
name | 接收string。代表数据库表名 |
con | 接收数据库连接 |
if_exists | 接收fail、replace、append。fail表示如果表名存在,则不执行写入操作;replace表示如果存在,则将原表替换掉;append则表示在源数据表的基础上追加数据。默认为fail |
index | 接收boolean。表示是否将行索引作为数据存入数据库。默认为True |
index_label | 接收string或者sequence。代表是否引用索引名称 |
dtype | 接收dict。代表写入的数据类型(列名为key,数据格式为values)。默认为None |
pandas提供了两种函数读取文本文件
read_table()
读取文本文件read_csv()
读取csv文件,即字符分隔文件#详细见官方文档
pd.read_table(filepath,sep='\t',header='infer',names=None,index_col=None,dtype=None,encoding=utf-8,engine=None,nrows=None)
pd.read_csv(filepath,sep=',',header='infer',names=None,index_col=None,dtype=None,encoding=utf-8,engine=None,nrows=None)
参数名称 | 说明 |
---|---|
filepath | 接收string。代表文件路径 |
sep | 接收string。代表分隔符 |
header | 接收int或sequence。表示将某行数据作为列名。默认infer,表示自动识别 |
names | 接收array。表示列名 |
index_col | 接收int、sequence、False。表示索引列的位置 |
dtype | 接收dict。代表写入的数据类型 |
engine | 接收c或者python。代表数据解析引擎。默认为c |
nrows | 接收int。表示读取前几行 |
对于结构化数据,通过to_csv()
函数实现以csv文件格式存储。
DataFrame.to_csv(
path_or_buf=None,
sep=",",
na_rep="",
float_format=None,
columns=None,
header=True,
index=True,
index_label=None,
mode="w",
encoding=None,
compression="infer",
quoting=None,
quotechar='"',
line_terminator=None,
chunksize=None,
date_format=None,
doublequote=True,
escapechar=None,
decimal=".",
)
常用参数说明:
参数名称 | 说明 |
---|---|
path_or_buf | 接收string。代表文件路径 |
sep | 接收string。代表分隔符,默认为’,’ |
na_rep | 接收string。代表缺失值,默认为"" |
columns | 接收list。代表写出的列名 |
header | 接收boolean。代表是否将列名写出。默认为True |
index | 接收boolean。表示索引名。代表是否将行名写出。默认为True |
index_label | 接收sequence。表示索引名 |
mode | 接收特定的string。代表数据写入模式。默认为w |
encoding | 接收特定的string。代表存储文件的编码格式 |
import pandas as pd
pd.read_excel(io, sheet_name=0, header=0, names=None, index_col=None, usecols=None, squeeze=False,dtype=None, engine=None, converters=None, true_values=None, false_values=None, skiprows=None, nrows=None, na_values=None, parse_dates=False, date_parser=None, thousands=None, comment=None, skipfooter=0, convert_float=True, **kwds)
#读取csv文件时,使用encoding='gbk'解决中文问题
1、io,Excel的存储路径
2、sheet_name,要读取的工作表名称
3、header, 用哪一行作列名
4、names, 自定义最终的列名
5、index_col, 用作索引的列
6、usecols,需要读取哪些列
7、squeeze,当数据仅包含一列
8、converters ,强制规定列数据类型
9、skiprows,跳过特定行
10、nrows ,需要读取的行数
11、skipfooter , 跳过末尾n行
DateFrame.to_excel(
excel_writer,
sheet_name="Sheet1",
na_rep="",
float_format=None,
columns=None,
header=True,
index=True,
index_label=None,
startrow=0,
startcol=0,
engine=None,
merge_cells=True,
encoding=None,
inf_rep="inf",
verbose=True,
freeze_panes=None,
)
with pd.ExcelWriter(r'{}\{}.xlsx'.format(path,'table_rank')) as writer:
table_rank.to_excel(excel_writer=writer,sheet_name='{}'.format('排名变化表'))
##2、掌握Series的常用操作
import pandas as pd
import numpy as np
pd.Series(['data=None', 'index=None', 'dtype=None', 'name=None', 'copy=False', 'fastpath=False'],)
name = ['蜘蛛侠', '灭霸', '奇异博士', '钢铁侠', '蝙蝠侠', '索尔']
age = [22, 3000, 33, 37, 40, 1500]
heroes_age = pd.Series(age,index=name) #索引index作为pd.Series()中的参数来为heroes_age指定索引
heroes_age
heroes_age.index
建立好Series之后,用一个新的列表(或者其他有序序列)赋值到该Series的索引对象中。
user_age = pd.Series([22, 3000, 33, 37, 40, 1500])
user_age.index = ['蜘蛛侠', '灭霸', '奇异博士', '钢铁侠', '蝙蝠侠', '索尔']
user_age
user_age.index = ['蜘蛛侠', '灭霸', '奇异博士', '钢铁侠', '蝙蝠侠', '索尔']
user_age.index.name = '英雄姓名'
user_age
user_age.index.name
In [6]: user_age.index.name = '英雄姓名'
In [7]: user_age
Out[7]:
英雄姓名
蜘蛛侠 22
灭霸 3000
奇异博士 33
钢铁侠 37
蝙蝠侠 40
索尔 1500
dtype: int64
#直接用pd.Series()中的name参数来设置
name = ['蜘蛛侠', '灭霸', '奇异博士', '钢铁侠', '蝙蝠侠', '索尔']
age = [22, 3000, 33, 37, 40, 1500]
heroes_age = pd.Series(age,index=name,name='英雄年龄')
heroes_age.name
#通过pd.Index方法先创建一个索引,再将索引添加到series中去
data=[22, 3000, 33, 37, 40, 1500]
index = pd.Index(['蜘蛛侠', '灭霸', '奇异博士', '钢铁侠','蝙蝠侠', '索尔' ], name="英雄姓名") #注意这里的Index中的"i"是大写
user_age = pd.Series(data=data, index=index, name="英雄年龄")
user_age
##运行结果
英雄姓名
蜘蛛侠 22
灭霸 3000
奇异博士 33
钢铁侠 37
蝙蝠侠 40
索尔 1500
Name: 英雄年龄, dtype: int64
import numpy as np
import pandas as pd
name = ['蜘蛛侠', '灭霸', '奇异博士', '钢铁侠', '蝙蝠侠', '索尔']
age = [22, 3000, 33, 37, 40, 1500]
heroes_age = pd.Series(age,index=name)
##索引
heroes_age[0]
heroes_age['蜘蛛侠']
##切片
heroes_age[0::2]
heroes_age['蜘蛛侠':'索尔':2]
#单独抽取某些数据
heroes_age[[1,2,4]]
heroes_age[['灭霸','奇异博士','蝙蝠侠']]
##get方法索引
heroes_age["蜘蛛侠"]
heroes_age.get("蜘蛛侠")
heroes_age.get("闪电侠", '不存在')
因为Series底层封装的也ndarray数组结构, 因此同样支持向量化操作, 可以利用
import numpy as np
import pandas as pd
name = ['蜘蛛侠', '灭霸', '奇异博士', '钢铁侠', '蝙蝠侠', '索尔']
age = [22, 3000, 33, 37, 40, 1500]
heroes_age = pd.Series(age,index=name)
heroes_age[heroes_age>100]
heroes_age[(heroes_age>1000)&(heroes_age<2000)]
# 提取年龄为偶数的数据
#提取年龄为偶数,且年龄小于100的英雄年龄
heroes_age[heroes_age%2==0]
heroes_age[(heroes_age%2==0)]
heroes_age[(heroes_age%2==0)&(heroes_age<100)] # 在多个逻辑条件下,用& 或者|
DataFrame 是一个带有索引的二维数据结构,每列可以有自己的名字,并且可以有不同的数据类型。你可以把它想象成一个 excel 表格或者数据库中的一张表,也可以将它想象成由多个Series拼接成的一个DataFrame,公用一个索引,它是最常用的 Pandas 对象。
import numpy as np
import pandas as pd
pd.DataFrame(data=None, index=None, columns=None, dtype=None, copy=False)
a=np.arange(1,10).reshape(3,3)
print(pd.DataFrame(a))
data = {
"年龄":[19, 3000, 30, 37, 40, 1500],
"出生地":["纽约皇后区", "泰坦星球","费城", "纽约", "哥谭", "阿斯加德" ]
}
#先将dataframe的索引创建,再将索引添加到dataframe中去
index = pd.Index(data=['蜘蛛侠', '灭霸', '奇异博士', '钢铁侠','蝙蝠侠', '索尔' ], name="英雄姓名")
user_info = pd.DataFrame(data=data,index=index )
print(user_info)
除了上面这种传入 dict 的方式构建外,我们还可以通过另外一种方式来构建。这种方式是先构建一个二维数组,然后再生成一个列名称列表。
data = [[19, "纽约皇后区"],
[3000, "泰坦星球"],
[30, "费城"],
[37, "纽约"],
[40, "哥谭"],
[1500, "阿斯加德"]]
columns = ["年龄", "出生地"]
index = pd.Index(data=['蜘蛛侠', '灭霸', '奇异博士', '钢铁侠','蝙蝠侠', '索尔' ], name="英雄姓名")
user_info = pd.DataFrame(data=data, index=index, columns=columns)
print(user_info)
DataFrame的基础属性:
DataFrame.values
添加一列的方法:只需要新建一个列索引,然后对该索引进行数据赋值即可
如果新列是依据原有的列生成的“衍生变量”,那么需要用到np.where(),比如要生成一列变量,将性别的“男”转化为“1”,“女”转化为“0”
import numpy as np
user_info
np.where(user_info.性别=="男",1,0) #这里返回的是numpy的ndarray
user_info["sex"]=np.where(user_info.性别=="男",1,0)
user_info
删除某行或者某列的数据用pandas提供的drop方法:
DataFrame.drop(label,axis=0,index=None,columns=None,level=None,inplace=False,erros='raise')
参数名称 | 说明 |
---|---|
labels | 接收string或者array。代表删除的行或列的标签 |
axis | 接收0或1.代表操作的轴向,(0或’行’)或(1或’列’) |
levels | 接收int或索引名。代表标签所在级别。 |
inplace | 接收boolean。代表操作是否对原数据生效。默认为False |
user_infor2.pop("列名")
如果我们想新修改user_infor2的列顺序,有两个方法:
df[列名组]
先用列表定义行的列名顺序,再按照这个新的顺序重新赋值回原DataFrame:
hehe=["年龄","性别","出生地"]
user_infor2[hehe] #这里只是返回新DataFrame,并没有修改原DataFrame
df.pop() + df.insert()
sex=user_infor2.pop("性别")
user_infor2.insert(1,"性别",sex)
user_infor2
更改DataFrame中的数据原理是将这部分数据提取出来,重新复制为新数据,需要注意的是:数据更改直接对源数据进行更改,操作无法撤销。如果做出更改,需要对更改条件进行确认或对数据进行备份。
通过上面的例子可以看出,我们创建新的列的时候都是在原有的 DataFrame 上修改的,也就是说如果添加了新的一列之后,原有的 DataFrame 会发生改变。
我们可以通过 assign 方法来创建新的一列,并返回一个新DataFrame
,不修改原DataFrame。
user_info.assign(新列 = 88) #自然对数(e为底)
DataFrame.assign()往往会搭配np.where()使用:
比如,依据原有的user_infor表,生成一个新的DataFrame,新的DataFrame新增一列变量,如果英雄性别为男,年龄增加10岁,性别为女增加5岁,新列列名为“新年龄”。
DataFrame的基本查看方式
DataFrame['列名']
、DataFrame.属性名
DataFrame['列名'][:5]
DataFrame[['列名1','列名2']][:5]
DataFrame[:][:5]
DataFrame.head(n)
、DataFrame.tail(n)
loc、iloc访问方式
DataFrame.loc[行索引名称会条件,列索引名称]
#条件切片
DataFrame.loc[DataFrame['列名']=='111','列名2']
DataFrame.iloc[行索引位置,列索引位置]
DataFrame.loc[(DataFrame['列名']=='111').values,[1,5]]
切片方法之ix:DataFrame.ix[行索引名称或位置,列索引名称或位置]
ix方法既可以接收索引名称,也可以接收索引位置,需注意:当索引名称和位置存在部分重叠时,ix默认优先识别名称。
#ix索引位置为闭区间
DataFrame.ix[2:6,5]
在使用 DataFrame 的过程中,经常会遇到修改列名,修改索引名、修改索引等情况。使用 rename 轻松可以实现。
user_infor2.index.name="heros names"
要将整个索引替换掉,只需要建立一个字典:
a=['蜘蛛侠', '灭霸', '奇异博士', '钢铁侠', '蝙蝠侠', '索尔']
b=["荷兰弟","乔什·布洛林","本尼迪克特·康伯巴奇","小罗伯特·唐尼","本·阿弗莱克","克里斯·海姆斯沃斯"]
c=dict(zip(a,b))
user_infor2=user_infor2.rename(index=c) #将行索引改为上面字典的映射关系
user_infor2.index.name="演员" #添加行索引名
user_infor2
修改列名只需要设置参数 columns。
user_infor2.columns.name="角色属性"
c={"年龄":"Age","性别":"Sex","出生地":"Birthplace"}
user_infor2=user_infor2.rename(columns=c)
user_infor2
有时候我们获取到数据之后,想要查看下数据的简单统计指标(最大值、最小值、平均值、中位数等),比如想要查看年龄的最大值,如何实现呢?
DataFrame中有两种方法可以实现:
user_info.Age.mean()
np.mean(user_info.Age)
那么,series能用哪些描述性统计的指标呢?——numpy中ndarray相应的函数都能用在这里
#numpy的函数都能用在这里
user_infor.Age.max()
user_infor.Age.idxmax()
user_infor.Age.idxmin()
user_infor.loc[user_infor.Age.idxmax()]
类似的,通过调用 min、mean、quantile、sum 方法可以实现最小值、平均值、中位数以及求和。可以看到,对一个 Series 调用 这几个方法之后,返回的都只是一个聚合结果。
user_info.Age.cumsum()
###例题
grade=pd.read_csv('student_grade.txt',sep='\t')
grade.head()
grade["数学"].mean()
grade['数学'].std()
t=grade[['数学','语文','英语']]
grade['总分1']=np.sum(t,axis=1)
grade['总分2']=grade.英语+grade.数学+grade.语文
grade
grade['差值']=grade.数学-grade.语文
grade['差值']=grade.差值.abs()
grade.head(5)
方法名称 | 说明 | 方法名称 | 说明 |
---|---|---|---|
min | 最小值 | max | 最大值 |
mean | 均值 | ptp | 极差 |
median | 中位数 | std | 标准差 |
var | 方差 | cov | 协方差 |
sem | 标准误差 | mode | 众数 |
skew | 样本偏度 | kurt | 样本峰度 |
quantile | 四分位数 | count | 非空数值数目 |
describe | 描述统计 | mad | 平均绝对离差 |
如果想要获取更多的统计方法,可以参见官方链接:Descriptive statistics (http://pandas.pydata.org/pandas-docs/stable/basics.html#descriptive-statistics)
虽然说常见的各种统计值都有对应的方法,如果我想要得到多个指标的话,就需要调用多次方法,是不是显得有点麻烦呢?
Pandas 设计者自然也考虑到了这个问题,想要一次性获取多个统计指标,只需调用 describe 方法即可
# 只支持数值列
grade.describe()
#直接调用 describe 方法后,会显示出数字类型的列的一些统计指标,如 总数、平均数、标准差、最小值、最大值、25%/50%/75% 分位数。
user_infor.describe(include=["object"]) #显示数据类型是object的字段信息
#结果展示了非数字类型的列的一些统计指标:总数,去重后的个数、最常见的值、最常见的值的频数。
频数统计:
user_infor['Birthplace'].value_counts()
如果想要获取某列最大值或最小值对应的索引,可以使用 idxmax 或 idxmin 方法完成。
user_infor.Age.idxmin() #注意区分,ndarray对应方法为np.argmin()
如果想要转换数据类型的话,可以通过 astype 来完成。
比如,想将年龄的数据类型从"int64"转为"float":
user_infor2.Age = user_infor2.Age.astype(float) #用dtype就要写成"float64",记得加双引号
user_infor2.info()
user_infor2
有时候会涉及到将 object 类型转为其他类型,常见的有转为数字、日期、时间差。 Pandas 中分别对应 to_numeric、to_datetime、to_timedelta 方法。 比如,如果我们给user_infor增加了一列新的字段“身高”
user_infor2["Height"] = ["175", "270", "178", "177", "185", "188", "168"]
#转换为数字
pd.to_numeric(user_infor2.Height)
user_infor2["Height"] = pd.to_numeric(user_infor2.Height)
##对身高字段进行统计描述
user_infor2["Height"].describe()
如果身高里面多了一些"cm"的字符,使用Series.to_numeric()会转换失败:
这时候可以通过Series.to_numeric()方法里面errors参数的设定来进行区分处理,errors可以设置参数’ignore’, ‘raise’, ‘coerce’:
user_infor2["Height"] = ["175", "270cm", "178cm", "177", "185", "188cm", "168"]
user_infor2["Height"] = pd.to_numeric(user_infor2.Height,errors="coerce")
user_infor2["Height"] = ["175", "270cm", "178cm", "177", "185", "188cm", "168"]
user_infor2["Height"] = pd.to_numeric(user_infor2.Height,errors="ignore")
user_infor2
在多数情况下,对时间类型数据进行分析的前提就是将原本为字符串的时间转换为标准时间。pandas继承了NumPy库和datetime库的时间相关模块,提供了6中时间相关的类。
类名称 | 说明 |
---|---|
Timestamp | 最基础的时间类。表示某个时间点。绝大多数的场景中的时间数据都是Timestamp |
Period | 表示单个时间跨度,或者某个时间段,例如某一天、某一小时等 |
Timedelta | 表示不同单位的时间,例如1d、1.5h等,而非具体的某个时间段 |
DatetimeIndex | 一组Timestamp构成的index,可以用来作为Series或者DataFrame的索引 |
PeriodtimeIndex | 一组Period构成的index,可以用来作为Series或者DataFrame的索引 |
TimedeltaIndex | 一组Timedelta构成的index,可以用来作为Series或者DataFrame的索引 |
Timestamp:将与时间相关的字符串转为Timestamp。pd.to_datetime()
还可以将原时间数据提取出来转换为DatetimeIndex 、PeriodtimeIndex
pd.DatetimeIndex()
、pd.PeriodIndex(Series,freq='S')
,转换为PeriodIndex的时候,需要通过freq参数指定时间间隔,常用的时间间隔有Y、M、D、H、T、S。两个函数可以用来转换数据,还可以用来创建时间序列数据。
参数名称 | 说明 |
---|---|
data | 接收array。表示DatetimeIndex的值 |
freq | 接收string。表示时间的间隔频率 |
start | 接收string。表示生成规则时间数据的起点 |
periods | 表示需要生成的周期数目 |
end | 接收string。表示生成规则时间数据的终点 |
tz | 接收timezone。表示数据的市区 |
name | 接收int或string。指定DatimeIndex的名字 |
DatetimeIndex用来指代一系列时间点的一种数据结构
PeriodIndex用来指代一系列时间段的数据节后-
在多数涉及与时间相关的数据处理、统计分析的过程中,都需要提取实践中的年份、月份等数据。
属性名称 | 说明 | 属性名称 | 说明 |
---|---|---|---|
year | 年 | week | 一年中第几周 |
month | 月 | quarter | 季节 |
day | 日 | weekofyear | 一年中第几周 |
hour | 小时 | dayofyear | 一年中第几天 |
minute | 分钟 | dayofweek | 一周第几天 |
second | 秒 | weekday | 一周第几天 |
date | 日期 | weekday_name | 星期名陈 |
time | 时间 | is_leap_year | 是否闰年 |
结合python列表推导式,可以实现对DataFrame某一列时间信息数据的提取
[i for i in DataFrame['lock_time']]
pd.DatetimeIndex().weekday_name
,需要注意的是:PeriodIndex相比于DatetimeIndex少了weekdar_name属性,所以不能用该属性提取星期名称,可以通过weekday属性,而后将06分别复制为MondaySundayTimedelta类是时间相关类中的一个异类,不仅能够使用正数,还能使用负数表示单位时间。
类的周期名称、对应单位及说明
周期名称 | 单位 | 说明 |
---|---|---|
weeks | 无 | 星期 |
days | D | 天 |
hours | h | 小时 |
minutes | m | 分 |
seconds | s | 秒 |
milliseconds | ms | 毫秒 |
microseconds | us | 微秒 |
nanoseconds | ns | 纳秒 |
#将时间数据向后平移一天
time1 = DataFrame['time'] + pd.Timedelta(days=1)
#时间数据相减,减去2017年1月1日0点0时0分0秒
timedelta = DataFrame['time'] - pd.to_datetime('2017-1-1')
groupby方法提供的是分组聚合步骤中的拆分功能,能够根据索引或者字段对数据进行分组。
DataFrame.groupby(
by=None,
axis=0,
level=None,
as_index=True,
sort=True,
group_keys=True,
squeeze=False,
observed=False,
**kwargs
)
参数名称 | 说明 |
---|---|
by | 接收llist、string、mapping、generator。用于确定分组的依据。如果传入的是函数,则对索引进行计算并分组;如果传入的是字典或Series,则字典或Series的值用来作为分组依据;如果传入一个NumPy数组,则数据的元素作为分组依据;如果传入的是字符串或者字符串列表,则使用这些字符串所代表的字段作为分组依据 |
axis | 接收int。表示操作的轴向,默认为0 |
level | 接收int或索引名。代表标签所在级别。默认为None |
as_index | 接收boolean。表示聚合后的聚合标签是否以DataFrame索引形式输出,默认为True |
sort | 接收boolean。表示是否对分组依据、分组标签进行排序、默认为True |
group_keys | 接收boolean。表示是否显示分组标签的名称,默认为True |
squeeze | 接收boolean。表示是否在允许的情况下对返回数据进行降维。默认为False |
分组后结果并不能直接查看,而后被存于内存中,输出的内存地址。是pandas提供的一种对象,Groupby对象常用的描述性统计方法及说明:
方法名称 | 说明 |
---|---|
count | 计算分组的数目,包括缺失值 |
head | 返回每组的前n个值 |
max | 返回每组的最大值 |
mean | 返回每组的均值 |
median | 返回每组的中位数 |
cumcount | 对每个分组的组员进行标记,0~n-1 |
size | 返回每组的大小 |
min | 返回每组的最小值 |
std | 返回每组的标准差 |
sum | 返回每组的和 |
detailGroup = DataFrame[['列名1','列名2','列名3']].group(DataFrame['列名1']).mean()
detailGroup = DataFrame.group(['列名1'])['列名1','列名2','列名3'].mean()
DataFrame.agg(func,axis=0,*args,**kwargs)
DataFrame.aggregate(func,axis=0,*args,**kwargs)
参数名称 | 说明 |
---|---|
func | 接收list、dict、function。表示应用于每行或每列的函数 |
axis | 接收0或1。代表操作的轴向,默认为0 |
#使用agg求出当前数据对应的统计量
DataFram.agg([np.sum,np.mean])
#分别求出一个字段的总和,另一个字段的均值
DataFrame.agg({'字段1':np.sum,'字段2':np.mean})
#agg里面也可以传入自定义函数
#agg方法对分组数据使用不同的聚合函数
DataFrame.groupby(by='列名').agg({'列名2':np.count,'列名3':np.sum})
DataFrame.apply(
func, #接收传入的函数
axis=0, #操作的轴向
broadcast=None, #是否进行广播
raw=False, #是否将ndarray对象传递给函数
reduce=None, #表示返回值的格式
result_type=None,
args=(),
**kwds
)
DataFrame.groupby(by='列名').apply(np.mean)
DataFrame.transform(func)
,可以对整个DataFrame进行操作
pd.pivot_table(
data, #接收DataFrame
values=None, #接收string。指定要聚合的数据字段名
index=None, #接收string、list。表示行分组键
columns=None, #接收string、list。表示列分组键
aggfunc="mean", #接收函数,表示聚合函数
fill_value=None, #填充缺失值
margins=False, #接收boolean。表示汇总开关
dropna=True, #是否删除权威NaN的列
margins_name="All",
observed=False,
)
DataFrame.pivot_table(
values=None,
index=None,
columns=None,
aggfunc="mean",
fill_value=None,
margins=False,
dropna=True,
margins_name="All",
observed=False,
)
交叉表是一种特殊的透视表,主要用于计算分组频率。
pd.crosstab(
index, #接收string、list。表示行索引建
columns, #接收string、list。表示列索引建
values=None,#接收array,表示聚合数据
rownames=None,#表示行分组键名
colnames=None,#表示列分组键名
aggfunc=None, #表示聚合函数
margins=False,#汇总功能的开关,默认为True
margins_name="All",
dropna=True, #是否删除全为NaN的列,默认为False
normalize=False,#是否对值进行标准化。默认为False
)
堆叠就是简单的把两个表拼在一起,也被称为轴向连接、绑定或连接。
pd.concat(
objs, #接收合并对象
axis=0, #0代表纵向合并
join="outer", #表示其他轴上的索引是按交集(inner)还是并集(outer)合并
join_axes=None, #接收Index对象,表示用于其他n-1条轴的索引
ignore_index=False, #是否不保留连接轴上的索引
keys=None,
levels=None,
names=None,
verify_integrity=False,
sort=None,
copy=True,
)
pd.concat([user_infor,user_infor],axis=0)
pd.concat([user_infor,user_infor],axis=1)
DataFrame.append(other, ignore_index=False, verify_integrity=False, sort=None)
user_infor.append(user_infor)
pd.merge(
left,
right,
how="inner", #连接方式
on=None,
left_on=None, #左表主键名
right_on=None, #右表主键名
left_index=False,
right_index=False,
sort=False,
suffixes=("_x", "_y"),
copy=True,
indicator=False,
validate=None,
)
pd.merge('left', 'right', "how='inner'", 'on=None', 'left_on=None', 'right_on=None)
left:仅使用左框架中的键,类似于SQL左外连接;保留关键顺序
pd.merge(user_info_01,user_info_02,how="left",left_on="Hero Name",right_on="英雄名")
right:仅使用右框架中的键,类似于SQL右外连接;保留关键顺序
pd.merge(user_info_01,user_info_02,how="right",left_on="Hero Name",right_on="英雄名")
outer:使用来自两个帧的键的并集,类似于SQL full outer加入;按字典顺序排序键
inner:使用两个帧的交集,类似于SQL内部加入;保留左键的顺序
pd.merge(user_info_01,user_info_02,how="inner",left_on="Hero Name",right_on="英雄名")
new_infor=pd.merge(user_info_01,user_info_02,how="right",left_on="Hero Name",right_on="英雄名")
new_infor=new_infor.drop("英雄名",axis=1)
a={"演员":"Actor or Actress"}
new_infor=new_infor.rename(columns=a)
new_infor.iloc[7,:]=["黑寡妇",35,"女","斯大林格勒","枪械"]
new_infor["Age"]=new_infor["Age"].astype(int)
new_infor
DataFrame.join(self, other, on=None, how="left", lsuffix="", rsuffix="", sort=False)
数据分析和处理过程中偶尔会出现两份数据的内容几乎一致的情况,但是某些特征一张表上是完整的,另一个表是缺失的。这是处理将数据一一对比然后填充的方法以外,还可以进行重叠合并数据。
df.combine_first(other)
,other表示参与重叠合并的另一个表数据重复会导致数据的方差变小,数据分布发生较大变化。缺失会导致样本信息减少,不仅增加了数据分析的困难,而且会导致数据分析结果产生偏差。异常值则会产生"伪回归"。
记录重复,一个或多个特征的某几条记录的值完全相同
DataFrame.drop_duplicates(subset=None, keep="first", inplace=False)
,该方法仅对DataFrame、Series有效
参数名称 | 说明 |
---|---|
subset | 接收string、sequence。表示去重的列,默认为全部列 |
keep | 接收特定的string。表示重复时保留第几个数据。first、last、false |
inplace | 接收boolean。表示是否在原表上进行操作。默认为False |
特征重复,存在一个或多个特征名称不同,但数据完全相同
相似度矩阵进行特征去重:该方法只能对数值型重复特征去重
利用特征间的相似度将两个相似度为1的特征去除一个。在pandas中,相似度计算方法为corr
。使用该方法计算相似度时默认为pearson法,可以通过method参数进行调节,还支持spearman
和kendall
法。
通过DataFrame.equals
进行特征去重
#作出特征相等矩阵
df.loc[i,j] = df.loc[:,i].equals(df.loc[:,j])
#遍历找出重复的列
if df.iloc[k,l]:
#删除重复列
df.drop(df.columns[l])
某一列是否有重复值
df_new_1 = df_new.groupby(['User_id'])['Merchant_id'].nunique()
#在同一个'User_id'下,'Merchant_id'有多少个
df_new_1 = df_new.groupby(['User_id']['Merchant_id'].value_counts()
df_new_1 = df_new.groupby(['User_id'])['Merchant_id'].unique()
#返回具体的unique值
在了解缺失值(也叫控制)如何处理之前,首先要知道的就是什么是缺失值?直观上理解,缺失值表示的是“缺失的数据”。
可以思考一个问题:是什么原因造成的缺失值呢?其实有很多原因,实际生活中可能由于有的数据不全所以导致数据缺失,也有可能由于误操作导致数据缺失,又或者人为地造成数据缺失。
在DataFrame中被当作是缺失值来处理的有:
其实如果DataFrame中存在Python中的None对象,一旦转化为dtype类型数据(object类型除外),None对象都会转成np.nan。
df_01=pd.DataFrame([1,2,None]) #在None转化为NaN过程中,object对象转化为float64,因为"NaN"是特殊的浮点数
df_01
df_01[0].dtype
##
type(np.nan)
df_01=pd.DataFrame([1,2,np.nan])
df_01
df_01[0].dtype
ser_01=pd.Series(range(2),dtype=object) #在None转化为NaN过程中,object对象不会转化为float64
ser_01[0]=None
ser_01
df.isnull().sum()
识别缺失值方法、df.notnull().sum()
识别非缺失值方法删除法
删除法简单易行,但是会引起数据结构的变动,样本量的减少
删除法分为删除观测记录和删除特征两种。属于通过减少样本量来换取信息完整度的一种方法,pandas提供了dropna
方法,通过参数控制,既可以删除观测记录,也可以删除特征
df.dropna(axis=0, how="any", thresh=None, subset=None, inplace=False)
参数名称 | 说明 |
---|---|
axis | 接收0或1.表示轴向,0表示行,1表示列 |
how | 接收特定的string。表示删除形式。any表示只要有缺失值就删除;all表示全部为缺失值时才删除 |
subset | 接收array。表示要进行去重的列/行。默认为所有 |
inplace | 接收boolean。表示是否在原表上操作 |
参数how
user_info_01.dropna(axis=1,how="all") #how="all"只有当该列(或行)全都为缺失值时,才会将该列删除
# user_info_01.dropna(axis=1,how="any") #how="any"只有当该列(或行)有一个缺失值,就会将该列删除
参数thresh
thresh参数设置的是:你想至少留下多少非缺失值!
user_info_01.dropna(thresh=8) #thresh=8只有当该行(可以设置axis=1来处理列)有8缺失值以上,就会将该行删除
参数subset
subset设定一个子集,子集中的列作为剔除缺失值的参考列:
user_info_01.dropna(axis=0,how="any")
user_info_01.dropna(axis=0,how="any",subset=["Height","Weight"])
user_info_01.dropna(axis=0,how="any",subset=["Birthplace","Weapon"])
##如何删除user_info_01中缺失值超过45%的字段。
user_info_01.dropna(axis=1,thresh=user_info_01.shape[0]*(1-0.45))
替换法
替换法难度较低,但是会影响数据的标准差,导致信息量的变动
替换法指用一个特定的值替换缺失值。特征分为数值型和类别型,两者出现缺失值时的处理方法也不同。
df.fillna(
value=None,
method=None,
axis=None,
inplace=False,
limit=None,
downcast=None,
**kwargs
)
参数名称 | 说明 |
---|---|
value | 接收scalar、dict、Series、DataFrame。表示用来替换缺失值的值。 |
method | 接收特定的string。backfill、fill表示使用下一个非缺失值来填补缺失值 |
axis | 接收0或1。表示轴向,默认为1 |
inplace | 接收boolean。是否在原表上进行操作 |
limit | 接收int。表示填补缺失值个数的上限。超过则不进行填补 |
插值法
pandas提供了interpolate的插值方法,能够进行上述部分的插值操作,但是Scipy库的interpolate
模块更加全面。
import numpy as np
from scipy import interpolate
inter_1d = interpolate.interp1d(x,y,kind='linear')
large = interpolate.lagrange(x,y)
spline = interpolate.make_interp_spline(x, y, k=3, t=None, bc_type=None, axis=0,check_finite=True)
BI = interpolate.BarycentricInterpolator(x,y)
df.replace()
None、np.nan、NaT(时间数据类型的缺失值) 这些都是缺失值。
但是这些在 Pandas 的眼中是缺失值,有时候在我们人类的眼中,某些异常值我们也会当做缺失值来处理。 例如,在我们的存储的用户信息中,假定我们限定用户都是青年,出现了年龄为 40 的,我们就可以认为这是一个异常值。
再比如,我们都知道性别分为男性(male)和女性(female),在记录用户性别的时候,对于未知的用户性别都记为了 “unknown”,很明显,我们也可以认为“unknown”是缺失值。
此外,有的时候会出现空白字符串,这些也可以认为是缺失值。
对于上面的这种情况,我们可以使用 replace 方法来替换缺失值。
user_info_01.iloc[::2,4]="unknown"
user_info_01
如果我们想要将上面DataFrame中所有的"unknown"都转为pandas能识别的缺失值形式np.nan,可以使用df.replace()的方法:
user_info_01.replace("unknown",np.nan)
指定到"Birthplace"这一列来进行替换缺失值,也是可以的:
user_info_01["Birthplace"]=user_info_01["Birthplace"].replace("unknown",np.nan)
异常值是指数据中个别的数值明显偏离其余的值,有时也称为离群点,检测异常值就是检验数据中是否有输入错误以及是否有含有不合理的数据。
3σ原则
该原则就是先假设一组检测数据只含有随机误差,对原始数据进行计算处理得到标准差,然后按一定的概率确定一个区间,认为误差超过这个区间就属于异常。这种处理方法仅适用于正态或者近似正态分布的样本数据。
箱线图分析
箱线图提供了识别异常值的一个标准,即异常值被定义为小于QL-1.5IQR或者大于QU+.5IQR的值。QL为下四分位数,QU为上四分位数,IQR为四分位数间距,是QU与QL之差。
不同特征之间往往具有不同的量纲,由此造成的数值间的差异可能很大,在涉及空间距离计算或者梯度下降等情况时,不对其进行处理会影响数据分析结果的准确性。
离差标准化是对原始数据的一种线性变换,结果是将原始数据的数值映射到[0,1]区间:
X ∗ = X − m i n m a x − m i n X^{*}=\frac{X-min}{max-min} X∗=max−minX−min
标准差标准化也叫零均值标准化或z分数标准化,经过改方法处理的数据均值为0,方程为1:
X ∗ = X − X ‾ δ X^{*}=\frac{X-\overline{X}}{\delta} X∗=δX−X
通过移动数据的小数位数,将数据映射到区间[-1,1],移动的小数位数取决于数据的绝对值的最大值:
X ∗ = X 1 0 k X^{*}=\frac{X}{10^{k}} X∗=10kX
pandas库中的get_dummies
函数对类别型特征进行哑变量处理
pd.get_dummies(
data, #接收需要进行哑变量处理的数据
prefix=None, #哑变量化后列名的前缀
prefix_sep="_", #前缀连接符
dummy_na=False, #是否为NaN值添加一列
columns=None, #需要编码的列名
sparse=False, #虚拟列是否是稀疏的
drop_first=False,#是否通过从k个分类级别中删除第一级来获得k-1个分类级别
dtype=None,
)
连续特征的离散化就是在数据的取值范围内设定若干个离散的划分点,将取值范围划分为一些离散化的区间,最后用不同的符号或者整数值代表落在每个子区间中的数据值。因此离散化涉及两个子任务:
等宽法
将数据的值域分成具有相同宽度的区间,区间个数由数据本身的特点决定或者由用户指定。
pd.cut(
x,
bins,
right=True,
labels=None,
retbins=False,
precision=3,
include_lowest=False,
duplicates="raise",
)
参数名称 | 说明 |
---|---|
x | 接收需要离散化的数据 |
bins | 接收int、list、array、tuple。int表示离散化后的数目;序列类型表示进行切分的区间,每两个数的间隔为一个区间 |
right | 代表右侧是否为闭区间 |
labels | 离散化后各个类别的名称 |
retbins | 是否返回区间的标签 |
precision | 显示标签的精度 |
pd.cut(user_infor['Age'], 7)
cut 自动生成了等距的离散区间,如果自己想定义也是没问题的。
pd.cut(user_infor.Age, [0, 18, 60, 100,5000])
有时候离散化之后,想要给每个区间起个名字,可以在pd.cut()中使用参数 labels 来指定。
a=pd.cut(user_infor.Age, [0, 18, 60, 100,150,5000], labels=["未成年", "成年", "老年人","超长寿","非人类"])
a
#既然pd.cut()返回的是一列Series,那么可以将其添加到原DataFrame中:
user_infor["Age"]=a
user_infor
除了可以使用 cut 进行离散化之外,qcut 也可以实现离散化。cut 是根据每个值的大小来进行离散化的,qcut 是根据每个值出现的次数来进行离散化,也就是基于分位数的离散化功能。
user_infor=pd.read_csv("new_infor.csv",index_col="Unnamed: 0")
user_infor
pd.qcut(user_infor.Age, 3)
等频法
def SameRateCut(data,k):
w = data.quantile(np.arange(0,1+1.0/k,1.0/k))
data = pd.cut(data,w)
return data
聚类分析法
在进行数据分析时,少不了进行数据排序。Pandas 支持两种排序方式:按轴(索引或列)排序和按实际值排序。
sort_index
方法默认是按照索引进行正序排的
user_info=pd.read_csv("new_infor.csv",index_col="Unnamed: 0")
user_infor.sort_index()
# 如果想要按照列进行倒序排,可以设置参数 axis=1 和 ascending=False。
user_infor.sort_index(axis=0, ascending=False)
如果想要实现按照实际值来排序,例如想要按照年龄排序,如何实现呢?
使用 sort_values 方法,设置参数 by=“age” 即可。
user_infor.sort_values(by='Age')
有时候我们可能需要按照多个值来排序,例如:按照年龄和城市来一起排序,可以设置参数 by 为一个 list 即可。
注意:list 中每个元素的顺序会影响排序优先级的。
user_infor.sort_values(by=["Age", "Birthplace"])
一般在排序后,我们可能需要获取最大的n个值或最小值的n个值,我们可以使用 nlargest 和 nsmallest 方法来完成,这比先排序再使用 head(n)方法快得多。
user_infor.Age.nlargest(3)
user_infor.Age.nsmallest(3)
虽说 Pandas 为我们提供了非常丰富的函数,有时候我们可能需要自己使用高级函数来实现自定义功能,并将它应用到 DataFrame 或 Series。常用到的函数有
map 是 Series 中特有的方法,通过它可以对 Series 中的每个元素实现转换。
如果我想通过年龄判断用户是否属于中年人(50岁以上为中年),通过 map 可以轻松搞定它。
##第一种方法
di = {
"纽约皇后区": "地球人",
"泰坦星球": "外星人",
"费城": "地球人",
"纽约": "地球人",
"哥谭":"地球人",
"阿斯加德":"外星人",
"天堂岛":"地球人",
"斯大林格勒":"地球人"
}
user_infor['星球'] = user_infor.Birthplace.map(di)
#第二种方法
earth_city=['纽约','费城','纽约','哥谭','天堂岛',"斯大林格勒"]
def city(x):
if x in earth_city:
return "地球人"
else:
return "外星人"
user_infor=user_info.copy(deep=True)
user_infor['种族'] = user_infor.Birthplace.map(city)
user_infor
apply 方法既支持 Series,也支持 DataFrame,在对 Series 操作时会作用到每个值上,在对 DataFrame 操作时会作用到所有行或所有列(通过 axis参数控制)。
# 对 Series 来说,apply 方法 与 map 方法区别不大。
earth_city=['纽约','费城','纽约','哥谭','天堂岛',"斯大林格勒"]
def city(x):
if x in earth_city:
return "地球人"
else:
return "外星人"
user_infor['种族'] = user_infor.Birthplace.apply(city) #这里只是将上一小节中的Series.map()换成了.apply(),其余代码一样
user_infor
对 DataFrame 来说,apply 方法的作用对象是一行或一列数据(一个Series)
def re_max(x):
return x.max()
user_infor.apply(re_max, axis=0)
applymap 方法针对于 DataFrame,它作用于 DataFrame 中的每个元素,它对 DataFrame 的效果类似于 apply 对 Series 的效果。
#将'侠'替换成'人'
def replace(x):
x=str(x)
if x.find("侠")!=-1:
x=x.replace("侠","人")
return x
user_infor.applymap(replace)