Pandas需要先读取表格类型的数据,然后进行分析
读取csv文件数据:
import pandas as pd
filepatch=r"C:\Users\radiomumm\Desktop\sucai\nba.csv"
#读取csv文件数据
ratings=pd.read_csv(filepatch)
#查看文件开头几行
print(ratings.head())
#查看文件行列属性,(行,列)
print(ratings.shape)
#查看列名,返回的是一个列表
print(ratings.columns)
#查看索引列
print(ratings.index)
#查看每列数据的数据类型
print(ratings.dtypes)
读取txt文件数据,txt文件需要以行列行使储存数据:
import pandas as pd
filepatch=r"C:\Users\radiomumm\Desktop\sucai\nba.txt"
#自定义读取文件,sep=设置分隔符,header=设置标题行有无,names=设置自定义列名。
ratings=pd.read_csv(filepatch,sep="\t",header=None,names=['NAME', 'state'])
print(ratings.head())
读取excel文件数据:
import pandas as pd
filepatch=r"C:\Users\radiomumm\Desktop\sucai\bhlh112.xlsx"
ratings=pd.read_excel(filepatch)
print(ratings.head())
DataFrame:二维数据,整个表格,多行多列。
Series:一维数据,代表一行或一列。包含一组数据(不同数据类型)和一组与之相关的数据标签(索引)组成。
import pandas as pd
sl=pd.Series([1,"A",23,5.4])
# [out]
# 0 1
# 1 A
# 2 23
# 3 5.4
# dtype: object
#获取索引
print(sl.index)#"RangeIndex(start=0, stop=4, step=1)"
# 获取值数列
print(sl.values)#[1 'A' 23 5.4]
#更换索引列,创建一个具有标签的Series.
sl=pd.Series([1,"A",23,5.4],index=["a","b","c","d"])
print(sl.index)#Index(['a', 'b', 'c', 'd'], dtype='object')
#使用字典创建Series
dictdata={"a":123,"b":3234,"c":1.2,"d":"end"}
sl2=pd.Series(dictdata)
print(sl2)
# [out]
# a 123
# b 3234
# c 1.2
# d end
# dtype: object
print(sl2["a"])#查询一个值时,返回原生数据。
print(sl2[["a","b"]])#查询两个值时,返回一个Series。
①.常见的方法为第一章中的Pandas读取excel/csv/mysql
②.使用多个字典文件创建Dataframe
import pandas as pd
dataf={"name":["xiaohong","xiaozhang","xiangqiang"],
"age":[21,23,22],
"gender":["female","male","female"],
"school":["1s","3s","2s"]}
df=pd.DataFrame(dataf)
print(df)
# [out]
# name age gender school
# 0 xiaohong 21 female 1s
# 1 xiaozhang 23 male 3s
# 2 xiangqiang 22 female 2s
print(df.index)#RangeIndex(start=0, stop=3, step=1)
print(df.columns)#Index(['name', 'age', 'gender', 'school'], dtype='object')
如果只查询一列、一行,返回的是Series。
如果查询的说多列、多行,返回的是一个Dataframe。
print(df["age"])#返回的是Series
print(df[["age"]])#返回的是Dataframe
print(df[["age","school"]])
loc 基于行标签和列标签(x_label、y_label)进行索引,主要查询方法:
1.使用单个labe伯查询数据
2.使用值列表批查询
3.使用数伯区间进行范围查询
4.使用条件太达式查向
5.调用函数查询
loc先行后列,中间用逗号(,)分割。
import pandas as pd
# 0.数据的预处理
filepatch=r"C:\Users\radiomumm\Desktop\sucai\nba.csv"
#读取csv文件数据
df=pd.read_csv(filepatch)
#设置列索引,inplace=True直接改变df格式
df.set_index("NAME",inplace=True)
#将"SALSRY"中的"$45,780,966"格式修改为"45780966"数值格式,以便于就绪操作。
df.loc[:,"SALSRY"]=df["SALSRY"].str.replace("$","").str.replace(",","").astype("int32")
# 查询"Stephen Curry, PG"的薪资
print(df.loc["Stephen Curry, PG","SALSRY"])#返回单一值,"45780966"
# 查询"Stephen Curry, PG"的薪资和队伍
print(df.loc["Stephen Curry, PG",["SALSRY","TEAM"]])#返回一个Series
# 查询"Stephen Curry, PG"/"James Harden, SG"/"John Wall, PG"的薪资
print(df.loc[["Stephen Curry, PG","James Harden, SG","John Wall, PG"],"SALSRY"])#得到一个series
print(df.loc[["Stephen Curry, PG","James Harden, SG","John Wall, PG"],["SALSRY","TEAM"]])#得到一个Dataframe
【区间既包含开始,也包含结束】
print(df.loc["Stephen Curry, PG":"John Wall, PG","SALSRY"])#行index查询,前三行的薪资
print(df.loc["Stephen Curry, PG","TEAM":"SALSRY"])#列index查询,第一行的两列数据
print(df.loc["Stephen Curry, PG":"John Wall, PG","TEAM":"SALSRY"])#行和列同时使用区间查询
【bool列表的长度得等于行数或者列数】
# 查询薪资大于41018900的球员
print(df.loc[df["SALSRY"]>41018900,:])
# 查询薪资大于41018900的球员,且在"Los Angeles Lakers"队中。【每个条件由括号分隔】
print(df.loc[(df["SALSRY"]>41018900)&(df["TEAM"]=="Los Angeles Lakers"),:])
# 直接调用lambda函数,输入整个df,然后按条件筛选。
print(df.loc[lambda df :(df["SALSRY"]>41018900)&(df["TEAM"]=="Los Angeles Lakers"),:])
# 编写自己的函数进行查询,所有属于"Golden State Warriors"队的球员
def choose_maydata(df):
return df["TEAM"]=="Golden State Warriors"
print(df.loc[choose_maydata,:])
iloc 基于行索引和列索引(index,columns)都是从 0 开始
如果数据的行标签和列标签名字太长或不容易记,则用 iloc 很方便,只需记标签对应的索引即可。
print(df.iloc[0,2])#取出Stephen Curry, PG的薪资数据,"45780966"
print(df.iloc[0:2])#取前两行对应数据
print(df.iloc[:,0:2])#取前两列对应数据
print(df.iloc[0:2,0:2])#取前两行和前两列对应数据
print(df.iloc[[0,2],[0,1,2]])#取第一行和第三行、第一列和第四列对应的数据
【直接赋值/apply/assign/分条件赋值】
import pandas as pd
# 0.数据的预处理
filepatch=r"C:\Users\radiomumm\Desktop\sucai\nba.csv"
#读取csv文件数据
df=pd.read_csv(filepatch)
和上文提到的修改数值方法相同,将Series格式看作为dictionary直接赋值。
# 选中df中的"SALSRY"列,对改列进行重新赋值,赋值内容为去除"$"和","并转化为int32格式
df.loc[:,"SALSRY"]=df["SALSRY"].str.replace("$","").str.replace(",","").astype("int32")
# 新增列,球员上场位置。
df.loc[:,"positions_TYPE"]=df["NAME"].str.replace("\w* \w*,","")
# 修改球员名字后的上场位置。
df.loc[:,"NAME"]=df["NAME"].str.replace(",.*","")
这个函数需要自己实现,函数的传入参数根据axis来定,比如axis = 1,就会把一行数据作为Series的数据结构传入给自己实现的函数中,我们在函数中实现对Series不同属性之间的计算,返回一个结果,则apply函数 会自动遍历每一行DataFrame的数据,最后将所有结果组合成一个Series数据结构并返回。
实例:添加一列实例:薪资大于40000000的为高薪,低于10500000的为底薪,否则就是正常薪资。
def get_SALSRY(df):
if df["SALSRY"]>=40000000:
return "high"
elif df["SALSRY"]<=10500000:
return "low"
else:
return "normal"
df.loc[:,"hight_low"]=df.apply(get_SALSRY,axis=1)#第0轴沿着行的垂直往下,第1轴沿着列的方向水平延伸。
#使用value_counts()函数对该列进行计数
x=df["hight_low"].value_counts()
print(x)
能够同时新增多个列,返回一个新列,该对象除新列外,还包含所有原始列。【assgin不会改变原有df,因此需要重新赋值】
实例:添加一列球员人民币薪资
df=df.assign(RMB=lambda x :x["SALSRY"]*6.72)
按条件先选择数据,然后对这部分数据赋值新列
实例:PG球员薪资超过30000000认为是球星。
df["superstar"]=""
df.loc[df["SALSRY"]>=30000000,"superstar"]="star"
df.loc[df["SALSRY"]<30000000,"superstar"]="normal_player"
# print(df.head(120))
x=df["superstar"].value_counts()
print(x)
三类函数完成以上操作:
●isnll和notnull: 检测是否是空值,可用于df和series。
●dropna: 丢弃、删除缺失值
axis :删除行还是列,{0 or "index', 1 or 'columns’}, default 0
how :如果等于any则任何值为空都删除,如果等于al则所有值都为空才删除。
inplace :如果为True则修改当前df,否则返回新的df。
●fllna: 填充空值
value:用于填充的值,可以是单个值,或者字典(key是列名,value是值)。
method :等于il使用前一个不为空的值填充forword fll;等于bil使用后一个不为空的值填充backword fill。
axis: 按行还是列填充,{0 or index', 1 or 'columns'}
inplace :如果为True则修改当前df,否则返回新的df。
录入qPCR的分析数据(excel):
其中skiprows=num这一参数能够忽略设置的行数,即skiprows=1:忽略第一行。
import pandas as pd
filepatch=r"C:\Users\radiomumm\Desktop\sucai\qpcr.xlsx"
df=pd.read_excel(filepatch,skiprows=1)#skiprows=num,忽略前num行读取。
isnull返回的值均为True/False,适用于Dataframe和Series。
print(df.isnull())#返回整个Datafream中True/False,对应是否为空值。
print(df["SAMPLE"].isnull())#返回Series中True/False,对应是否为空值。
notull可用于筛选所有不为空值的行列
print(df.notnull())#返回整个Datafream中True/False,对应是否不为空值,与isnull函数相反。
print(df["SAMPLE"].notnull())#返回Series中True/False,对应是否不为空值,与isnull函数相反。
实例:返回"A1"列不为空值的所有行。
print(df.loc[df["A1"].notnull(),:])#筛选"A1"列不为空的所有行
dropna函数中axis="columns"表示列删除,how="all"表示删除全为空值的列,inplace=True表示对数据集本身进行修改。
axis参数:存在"columns"和"index"两种模式。即,一个删除列一个删除行。
how参数:存在"all"和"any"两种模式。使用"all"时删除全部为空值模式;使用"any"时为存在空值就删除模式。
实例:删除全部为空值的列。
df.dropna(axis="columns",how="all",inplace=True)
实例:删除全部为空值的行。
df.dropna(axis="index",how="all",inplace=True)
使用fillna函数对空值进行填充,需要用到inplace=True对原Dataframe进行修改。
fillna函数原理:【df.loc[:,“A1”]=df[“A1”].fillna(“NA”)】,还类似于字典形式。
对单一Series进行填充
df.fillna({"A1":0},inplace=True)
对多个Series进行填充
df.fillna({"A1":"NA","A2":"NA","A3":"NA","ACT1":"NA","ACT2":"NA","ACT3":"NA"},inplace=True)#实现多行填充
这里用到了fillna中的参数:ffill(forward fill)。即使用前面不为空的值进行填充。
实例:将NAME和SAMPLE中的缺失值进行填充
df.loc[:,"NAME"]=df["NAME"].fillna(method="ffill")
df.loc[:,"SAMPLE"]=df["SAMPLE"].fillna(method="ffill")
使用to_excel将数据保存为新的excel,保存时添加index=False能够避免生成行数列。
df.to_excel(r"C:\Users\radiomumm\Desktop\sucai\qpcr_clean.xlsx",index=False)
#数据的预处理
import pandas as pd
filepatch=r"C:\Users\radiomumm\Desktop\sucai\nba.csv"
df=pd.read_csv(filepatch)
df.loc[:,"SALSRY"]=df["SALSRY"].str.replace("$","").str.replace(",","").astype("int32")
Series.sort_ values(ascending=True, inplace=False)
参数:
print(df["SALSRY"].sort_values())#默认为True升序排序
print(df["SALSRY"].sort_values(ascending=False))#False降序排序
print(df["TEAM"].sort_values())#字符串同样能够排序,默认为a-z
DataFrame.sort values(by, ascending=True, inplace=False)
参数 :
print(df.sort_values(by="SALSRY"))#以SALSRY列对整个df进行排序,默认为True升序排序
print(df.sort_values(by="SALSRY",ascending=False))#以SALSRY列对整个df进行排序,默认为True升序排序
对df中多列值进行排列【多列排序时谁在前,优先排谁】
print(df.sort_values(by=["TEAM","SALSRY"],ascending=False))#先排"TEAM"再排"SALSRY"
print(df.sort_values(by=["SALSRY","TEAM"],ascending=False))
排序时分别指定升序降序
print(df.sort_values(by=["TEAM","SALSRY"],ascending=[False,True]))
pandas提供大量关于字符串常用方法:
https://pandas.pydata.org/docs/reference/series.html#string-handling
具体使用方法 :
使用方法:先获取Series的str属性, 然后在属性上调用函数。
只能在字符串列上使用,不能数字列上使用。
Dataframe.上没有str属性和处理方法。
Series.str并不是Python原生字符串,而是自己的一套方法,不过大部分和原生str很相似。
本节只挑选常用的部分语句演示:
获取Series的str属性,然后使用各种字符串处理函数
使用str的startswith、contains等bool类Series可以做条件查询
需要多次str处理的链式操作
使用正则表达式的处理
import pandas as pd
filepatch=r"C:\Users\radiomumm\Desktop\sucai\nba.csv"
df=pd.read_csv(filepatch)
使用replace函数,批量替换series中的特定字符串。
print(df["SALSRY"].str.replace("$","").str.replace(",",""))
condition=df["NAME"].str.startswith("Stephen")
# print((condition))#返回只含有True/False的bool series
print(df[condition])#返回筛选结果
print(df["NAME"].str.replace(", ","-").str.slice(-2))#其中slice就是切片用法,slice[-2]
#相当于
print(df["NAME"].str.replace(", ","-").str[-2:])#其中slice就是切片用法,slice[-2]
实例:添加一列球员打什么位置
def get_pos(x):
name,pos=x["NAME"].split(",")
return "{} is {}".format(name,pos)
df["infor"]=df.apply(get_pos,axis=1)
问题:如何还原原有的NAME信息?
1.使用替换的方法
df.loc[:,"infor"]=df["infor"].str.replace(" is ",",")
2.使用正则表达式
df.loc[:,"infor"]=df["infor"].str.replace(" \w\w ",",")
●axis=0或者"index":
如果是单行操作,就指的是某一行
如果是聚合操作,指的是跨行cross rows
●axis=1或者"columns" :
如果是单列操作,就指的是某一列
■如果是聚合操作,指的是跨列cross columns
按哪个axis,就是这个axis要动起来(类似被for遍历),其它的axis保持不动
创建3*4的dataframe:
import pandas as pd
import numpy as np
df=pd.DataFrame(np.arange(12).reshape(3,4),columns=["a","b","c","d"],index=["A","B","C"])
df.drop("a",axis=1,inplace=True)
df.drop("A",axis=0,inplace=True)
【反直觉:输出的不是每行的结果,而是每列的结果】
可以理解为:axis=0即传入行坐标输出的是列标题的结果,而axis=1传入列坐标,输出的是行标题结果。
实例:输出每列平均值
print(df.mean(axis=0))
实例:输出每行平均值
print(df.mean(axis=1))
实例:新增一列计算平均值
def get_mean_columns(x):
return (x["a"]+x["b"]+x["c"]+x["d"])/4
df["mean1"]=df.apply(get_mean_columns,axis=1)
index的用途总结:
import time
from sklearn.utils import shuffle
import pandas as pd
#数据的预处理,读取csv文件数据
filepatch=r"C:\Users\radiomumm\Desktop\sucai\nba.csv"
df=pd.read_csv(filepatch)
由于set_index会将索引列删除,因此设置drop=False使其保留在列表内。
df.set_index("TEAM",inplace=True,drop=False)
condition=df.loc[df["TEAM"]=="Golden State Warriors"]
print(condition)
2.使用index的方法查询,简化查询过程
condition=df.loc["Golden State Warriors"]
print(condition)
蓝色线:如果index是唯一的,Pandas会使用哈希表优化,查询性能为O(1)。
绿色线:如果index不是唯一的, 但是有序,Pandas会使用二分查找算法,查询性能为O(logN)。
黄色线:如果index是完全随机的,那么每次查询都要扫描全表,查询性能为O(N)。
# 将数据随机打散
df_shuffle=shuffle(df)
# 查看数据的index是否递增
print(df_shuffle.index.is_monotonic_increasing)#"Flase"
# 查看数据的index是可以用哈希
print(df_shuffle.index.is_unique)#"Flase"
#计算时间耗费
start=time.time()
print(df_shuffle.loc["Cleveland Cavaliers"])#"Running time: 0.00600123405456543 Seconds"
end=time.time()
print('Running time: %s Seconds'%(end-start))
# 将随机打散数据重新排序
df_shuffle_sorted=df_shuffle.sort_index()
# 查看数据的index是否递增
print(df_shuffle_sorted.index.is_monotonic_increasing)#"True"
# 查看数据的index是可以用哈希
print(df_shuffle_sorted.index.is_unique)#"Flase"
#时间耗费
start=time.time()
print(df_shuffle_sorted.loc["Cleveland Cavaliers"])#"Running time: 0.00699615478515625 Seconds"
end=time.time()
print('Running time: %s Seconds'%(end-start))
实例:两个series相加,相同索引相加,不相同的为NA。
s1=pd.Series([1,2,3,4],index=["a","b","c","d"])
s2=pd.Series([4,5,6,7,8],index=["c","d","f","w","q"])
print(s1+s2)
输出为:
a NaN
b NaN
c 7.0
d 9.0
f NaN
q NaN
w NaN
很多强大的索引数据结构
●Categoricallndex,基于分类数据的Index,提升性能;
●MutiIndex, 多维索引,用于groupby多维聚合后结果等;
●DatetimeIndex, 时间类型索引,强大的日期和时间的方法支持;
Pandas的Merge,栖当于Sql的Join, 将不同的表按key关联到一个表。
merge的语法:
【pd.merge(left, right,how=“inner”,on=None,left_on=None,right_on=None,left_index=False,right_ndex=False,sort=True,suffixes=(“_x”,“_y”),copy=True,indicator=False,validate=None)】
●left/right: 要merge的dataframe或者有name的Series
●how: join类型, “left, 'right, ‘outer’ , ‘inner’,默认为"inner”
●on: join的key, left和right都需要有这个key
●left_on: left的dataframe或者Series的key
●right_on: right的dataframe或者Series的key
●left_index/right_index: 使用index而不是普通的column做jion
●suffixes: 两个元素的后缀,如果列有重名,自动添加后缀,默认是(“_x”,“_y”)
使用网站MovieLens | GroupLens提供的电影评分数据:
输入数据:
import pandas as pd
#读取并重新分隔命名数据
df_ratings=pd.read_csv(r"C:\Users\radiomumm\Desktop\sucai\ml-1m\ratings.dat",sep="::",engine="python",names="User_id::Movie_id::Ratings::Timestamp".split("::"))
df_users=pd.read_csv(r"C:\Users\radiomumm\Desktop\sucai\ml-1m\users.dat",sep="::",engine="python",names="User_id::Gender::Age::Occupation::Zip-code".split("::"))
df_movies=pd.read_csv(r"C:\Users\radiomumm\Desktop\sucai\ml-1m\movies.dat",sep="::",engine="python",names="Movie_id::Title::Genres".split("::"))
print(df_movies.head(20))
print(df_users.head(20))
print(df_ratings.head(20))
left_on/right_on指的是按照两个数据集的指定key合并,how="inner"表示两组数据均包含选取key才保留。
df_ratings_users=pd.merge(df_ratings,df_users,left_on="User_id"
,right_on="User_id"
,how="inner")
print(df_ratings_users.head(20))
df_ratings_users_movies=pd.merge(df_ratings_users,df_movies,left_on="Movie_id"
,right_on="Movie_id"
,how="inner")
print(df_ratings_users_movies.head(120))
以下关系要正确理解:
●one-to-one:一对一关系,关联的key都是唯一的。
■比如(学号,姓名) merge (学号,年龄),结果条数为: 1*1
●one-to-many:一对多关系, 左边唯一key, 右边不唯一key。
■比如(学号,姓名) merge (学号, [语文成绩、数学成绩、英语成绩),结果条数为: 1*N
●many-to-many:多对多关系,左边右边都不是唯一的。
比如(学号,[语文成绩、数学成绩、英语成绩]) merge (学号, [篮球、足球、乓球]),结果条数为: M*N
实例:
left=pd.DataFrame({"sno":[232,211,231,413],
"age":[21,23,22,24]})
right=pd.DataFrame({"sno":[232,211,231,413],
"name":["xiaoz","xiaos","xiaow","xiaod"]})
pd_sum=pd.merge(right,left,on="sno")
print(pd_sum)
left=pd.DataFrame({"sno":[232,211,231,413],
"name":["xiaoz","xiaos","xiaow","xiaod"]})
right=pd.DataFrame({"sno":[232,232,232,211,211,211,231,231,231,413],
"grade":["语文99","数学92","英语87","语文92","数学32","英语17",
"语文29","数学34","英语27","英语97"]})
pd_sum=pd.merge(right,left,on="sno")
print(pd_sum)
left=pd.DataFrame({"sno":[232,211,211,231,231,231,413],
"爱好":["篮球 ","篮球","排球","台球","电竞","看球","游戏"]})
right=pd.DataFrame({"sno":[232,232,232,211,211,211,231,231,231,413],
"grade":["语文99","数学92","英语87","语文92","数学32","英语17",
"语文29","数学34","英语27","英语97"]})
pd_sum=pd.merge(right,left,on="sno")
print(pd_sum)
left join:以左边数据集为准,左数据集完全保留,右边数据集为空。
right join:右边数据集完全保留,左边数据集为空。
inner join:左右数据集交集。
outer join:左右数据集合集。
实例:
import pandas as pd
left=pd.DataFrame({"key":["K1","K2","K3","K4"],
"爱好1":["篮球 ","篮球","排球","台球"],
"B":["B1","B2","B3","B4"]})
right=pd.DataFrame({"key":["K3","K4","K5","K6"],
"爱好2":["篮球1 ","篮球2","排球3","台球4"],
"A":["A1","A2","A3","A4"]})
1.inner join,默认【左右两个数据集都存在时才输出】
print(pd.merge(left,right,how="inner"))
2.left join,【左边的都会出现在结果里,右边的如果无法匹配则为Null】
print(pd.merge(left,right,how="left"))
3.right join,【右边的都会出现在结果里,左边的如果无法匹配则为Null】
print(pd.merge(left,right,how="right"))
4.outer join,【左右两个数据集都会出现在结果里,匹配不上的为Null】
print(pd.merge(left,right,how="outer"))
实例 :
import pandas as pd
left=pd.DataFrame({"key":["K1","K2","K3","K4"],
"爱好":["篮球 ","篮球","排球","台球"],
"B":["B1","B2","B3","B4"]})
right=pd.DataFrame({"key":["K3","K4","K5","K6"],
"爱好":["篮球1 ","篮球2","排球3","台球4"],
"A":["A1","A2","A3","A4"]})
Pandas默认处理方法:会在 相同key后加上"_x"和"_y"
print(pd.merge(left,right,on="key"))
可以指定后缀:
print(pd.merge(left,right,on="key",suffixes=("_left","_right")))
批量合并相同格式的Excel、给DataFrame添加行、 给DataFrame添加列。
一句话说明concat语法:
●使用某种合并方式(innerlouter)
●沿着某个轴向(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: 是否忽略原来來的数据索引。
import pandas as pd
import warnings
warnings.filterwarnings("ignore")#忽略报警
df1=pd.DataFrame({"A":["A0","A1","A2","A3","A4","A5"],
"B":["B0","B1","B2","B3","B4","B5"],
"C":["C0","C1","C2","C3","C4","C5"],
"D":["D0","D1","D2","D3","D4","D5"],
"E":["E0","E1","E2","E3","E4","E5"],})
df2=pd.DataFrame({"A":["A10","A11","A12"],
"B":["B10","B11","B12"],
"C":["C10","C11","C12"],
"D":["D10","D11","D12"],
"E":["E10","E11","E12"],
"F":["F10","F11","F12"],})
concat默认参数为:axis=0,join=outer,ignore_index=False
dfs=[df1,df2]
df_sum=pd.concat(dfs)
print(df_sum)
# 在汇总表前加上特定的key
df_sum=pd.concat(dfs,keys=["一月","二月"])
print(df_sum)
#ignore_index=True能够忽略数据集原本的索引,并重新设置索引
df_sum=pd.concat(dfs,ignore_index="True")
print(df_sum)
#使用join="inner"过滤掉不匹配的列
df_sum=pd.concat(dfs,ignore_index="True",join="inner")
print(df_sum)
df_sum=pd.concat(dfs,axis=1)
print(df_sum)
#添加一列新的series
s1=pd.Series(list(range(4)),name="G")
df_sum=pd.concat([df1,df2,s1],axis=1)
print(df_sum)
#添加多列新的series
s2=df1.apply(lambda x:x["A"]+"_CG",axis=1)
s2.name="H"
df_sum=pd.concat([df1,s2,s1],axis=1)
print(df_sum)
append语法:
DataFrame.append(other, ignore_index=False)
append只有按行合并,没有按列合井.相当于concat按行的简形式。
●other: 单个datafrema、 series、 dict, 或者列表
●ignore_ index: 是否忽略掉原来的数据索引
df1=pd.DataFrame({"A":[1,2],
"B":[3,4]})
df2=pd.DataFrame({"A":[5,6],
"B":[7,8]})
df_sum=df1.append(df2,ignore_index=True)#忽略之前的索引
print(df_sum)
低性能版本,使用for循环【df每次都会重新赋值,如果数据很多会造成卡死】
df=pd.DataFrame(columns=["A"])
for i in range(5):
df=df.append({"A":i},ignore_index=True)
print(df)
高性能版本,使用for循环
df=pd.concat([pd.DataFrame([i],columns=["A"])for i in range(5)],ignore_index=True)
print(df)
Pandas提供了concat,merge,join和append四种方法用于dataframe的拼接,其区别如下:
详见:(13条消息) Pandas拼接操作(concat,merge,join和append)的区别_Yale曼陀罗的博客-CSDN博客_concat和append的区别
实例:
1.将一个大的Excel拆分成多个Excel
2.将多个小Excel合并成一个大的Excel并记录来源
12.0.1 创建工作文件夹和存放文件夹
work_dir="C:/Users/radiomumm/Desktop/sucai"
splits_dir=f"{work_dir}/splits"
import os
if not os.path.exists(splits_dir):
os.mkdir(splits_dir)
pass
import pandas as pd
#sheet_name=""可以指定读取sheet
df_source=pd.read_excel(r"C:\Users\radiomumm\Desktop\sucai\SNP_choose.xlsx",sheet_name="ALL")
print(df_source.index)#RangeIndex(start=0, stop=79958, step=1)
print(df_source.shape)#(79958, 29),该列表存在79958行,29列。
① 使用df.iloc方法,将一个大的daframe, 拆分成多个小dataframe
② 将使用dataframe.to_ excel保存每个小Excel
#拆分后的excel会分给一下用户:
user_names=["A","B","C","D","E","F","G"]
# 每个人的任务量
split_size=df_source.shape[0]//len(user_names)
if df_source.shape[0]%len(user_names)!=0:
split_size+=1
pass
# print(split_size)
df_subs=[]
for idx,user_name in enumerate(user_names):
#每个人开始的索引,0*split_size
begin=idx*split_size
#每个人结束的索引
end=begin+split_size
#使用iloc实现拆分
df_sub=df_source.iloc[begin:end]
#将每个子df存入列表
df_subs.append((idx,user_name,df_sub))#将脚标、分配人姓名、和表信息存入元组
for idx,user_name,df_sub in df_subs:
filename=f"{splits_dir}/aaaaa_{idx}_{user_name}.xlsx"
df_sub.to_excel(filename,index=False)
pass
import os
import pandas as pd
excel_names=[]
splits_path=r"C:\Users\radiomumm\Desktop\sucai\splits"
for excel_name in os.listdir(splits_path):
excel_names.append(excel_name)
# print(excel_names)
df_list=[]
for excel_name in excel_names:
#获取每个excel的路径名称
excel_path=f"{splits_path}/{excel_name}"
df_split=pd.read_excel(excel_path)
#将文件名替换好后得到“0_A”格式,使用切片[2:0]从第二个元素开始取
username=excel_name.replace("aaaaa_","").replace(".xlsx","")[2:]
# print(username,excel_name)
# 添加一列用户名
df_split["username"]=username
df_list.append(df_split)
pass
# print(df_concat.shape)
# print(df_concat["username"].value_counts())
# 4.将合并后的dataframe输出到excel
df_concat.to_excel(r"C:\Users\radiomumm\Desktop\sucai\df_concat.xlsx",index=False)
类似SQL:
select city.max(temperature) from city. weather group by city
groupby:先对数据分组,然后在每个分组上应用聚合函数、转换函数。
本次演示:
一、分组使用聚 合函数做数据统计
二、遍历groupby的结果理解执行流程
三、实例分组探索NBA数据
import pandas as pd
import numpy as np
filepatch=r"C:\Users\radiomumm\Desktop\sucai\nba.csv"
df=pd.read_csv(filepatch)
df.loc[:,"SALSRY"]=df["SALSRY"].str.replace("$","").str.replace(",","").astype("int32")
def get_pos(x):
name,pos=x["NAME"].split(",")
return pos
df["infor"]=df.apply(get_pos,axis=1)
df.groupby("TEAM").sum()
groupby中"TEAM"列和"infor"列成为数据的多级索引列。
df.groupby(["TEAM","infor"]).sum()
去除索引,变为普通的列
df.groupby(["TEAM","infor"],as_index=False).sum()
df.groupby("TEAM").agg([np.sum,np.mean,np.std])
查看特定数据列的统计情况
df.groupby("TEAM")["SALSRY"].agg([np.sum,np.mean,np.std])
或者
df.groupby("TEAM").agg([np.sum,np.mean,np.std])["SALSRY"]
df.groupby("TEAM").agg({"RK":np.sum,"SALSRY":np.mean})
team=df.groupby("TEAM")
print(team)#""
以上格式可以直接使用for遍历
for teamid,infor in team:
print(teamid)
print(infor)
使用get_group函数获取单个分组
team.get_group("Denver Nuggets")
team=df.groupby(["TEAM","infor"])
for teamid,inforpos in team:
print(teamid)
print(inforpos)
可以看到,teamid是一个元组,包含了分组情况。
使用get_group函数获取单个分组
team.get_group(("Denver Nuggets"," PG"))
查询group后的某几列,生成Series或者DF
print(team["RK"])#""
for teamid,inforpos in team["RK"]:
print(teamid)
print(inforpos)
1.按照队伍分类后查看每队最高薪球员,并画出柱状图
plt.xticks(rotation=90)设置x轴 标签倾斜度,plt.show( )用于显示。
import matplotlib.pyplot as plt
moneymax=df.groupby("TEAM",as_index=False)["SALSRY"].max()
# print(moneymax.head(20))
x=moneymax["TEAM"]
y=moneymax["SALSRY"]
plt.figure(figsize=(10,6))
# plt.plot(moneymax)
plt.bar(x,y,width=0.5,align="center",alpha=0.8)
plt.xticks(rotation=90)
plt.show()
2.按照队伍分类后查看每队最高、低薪球员和排名总和,并画出折线图
data=df.groupby("TEAM").agg({"RK":np.sum,"SALSRY":[np.max,np.min]})
# 使用matplotlib画图
plt.plot(data)
plt.xticks(rotation=90)
plt.legend()
plt.show()
# 使用Pandas画图
data.plot()
plt.xticks(rotation=90)
plt.show()
为什么要学习分层索引Mutilndex?
●分层索引:在一个轴向上拥有多个索引层级,可以表达更高维度数据的形式。
●可以更方便的进行数据筛选,如果有序则性能更好。
●groupby等操作的结果,如果足多KEY,结果是分层索引,需要会使用。
●一般不需要白己创建分层索引(Multilndex有构造函数但一般不用)
本次演示提纲:
一、Series的分层索引Multilndex
二、Series有多层索引怎样筛选数据?
三、DataFrame的多层索引Multilndex
四、DataFrame有多层索引怎样筛选数据?
从https://cn.investing.com/网站下载多个公司股票信息,并合并为一个csv文件:
import pandas as pd
workdir="C:/Users/radiomumm/Desktop/sucai"
dfbaba_path=f"{workdir}/groupby/BABA历史数据.csv"
dfbilbil_path=f"{workdir}/groupby/BILI历史数据.csv"
dfbaidu_path=f"{workdir}/groupby/BIDU历史数据.csv"
dfjd_path=f"{workdir}/groupby/JD历史数据.csv"
dfnf_path=f"{workdir}/groupby/NFLX历史数据.csv"
dfbaba=pd.read_csv(dfbaba_path)
dfbilbil=pd.read_csv(dfbilbil_path)
dfbaidu=pd.read_csv(dfbaidu_path)
dfjd=pd.read_csv(dfjd_path)
dfnf=pd.read_csv(dfnf_path)
dfbaba.loc[:,"名字"]="baba"
dfbilbil.loc[:,"名字"]="bilbil"
dfbaidu.loc[:,"名字"]="baidu"
dfjd.loc[:,"名字"]="jingdong"
dfnf.loc[:,"名字"]="nelfx"
dfs=[dfbaba,dfbaidu,dfbilbil,dfjd,dfnf]
dfall=pd.concat(dfs,ignore_index=True)
dfall.to_csv(f"{workdir}/groupby/汇总.csv",encoding="gbk",index=False)
查看数据基本信息 :
# 查看数据结构
print(dfall.shape)#"(25, 8)"
# 查看公司名字
print(dfall["名字"].unique())#"['baba' 'baidu' 'bilbil' 'jingdong' 'nelfx']"
# 查看索引
print(dfall.index)
使用groupby函数分组
ser=dfall.groupby(["名字","日期"])["收盘"].mean()
print(ser)#多维索引中,空白意味着和上面的值一致。
print(ser.index)#MultiIndex,列表内包含元组,元组中包含两个分组对象。
使用unstack函数降低索引层次,将二级或次级索引变为列,原本的series变为dataframe。
ser.unstack()
使用reset_index函数将分组索引还原,变为dataframe,前两列为多层搜索引,后一列为索引的值列。
ser.reset_index()
使用loc函数进行索引,可以索引第一层或多层。
print(ser.loc["bilbil"])
print(ser.loc["bilbil","2022年5月2日"])
跳过第一层筛选第二层时需要以下两种格式
print(ser.loc[:,"2022年5月2日"])
print(ser.loc[slice(None),"2022年5月2日"])
使用set_index对Dataframe进行分层索引
dfall.set_index(["名字","日期"],inplace=True)
print(dfall)
对索引进行排序,先按照第一层索引排序
dfall.sort_index(inplace=True)
print(dfall)
【重点理解】:
●元组(key1,key2)代表筛选多层索引,其中key1是索引第一级, key2是第二级, 比如key1=“jingdong”, key2=“2019-10-02”
●列表[key1,key2]代表同- 层的多个KEY,其中key1和key2是并列的同级索引,比如key1=“jingdong”, key2=“BIDU”
只筛选第一层的某个值
print(dfall.loc["baidu"])
筛选多层索引的所有列,传入元组
print(dfall.loc[("baidu","2022年5月6日"),:])
筛选多层索引的特定列,传入元组
print(dfall.loc[("baidu","2022年5月6日"),"交易量"])
同一层多个索引值的筛选,取出两个对像
print(dfall.loc[["baidu","bilbil"],:])
混合筛选,两个第一层索引值和一个第二层索引值
print(dfall.loc[(["baidu","bilbil"],"2022年5月6日"),:])
混合索引只输出一列
print(dfall.loc[(["baidu","bilbil"],"2022年5月6日"),"涨跌幅"])
多层混合
print(dfall.loc[(["baidu","bilbil"],["2022年5月5日","2022年5月6日"]),"涨跌幅"])
需要只对第二层索引进行筛选,保留一层索引的方法
print(dfall.loc[(slice(None),["2022年5月5日","2022年5月6日"]),"涨跌幅"])
恢复索引为普通的列
dfall.reset_index(inplace=True)
print(dfall)
数据转换函数对比: map、apply、 aplymap:
map:只用于Series,实现每个值->值的映射。
apply:于Series实现每个值的处理,用于Dataframe实现某个轴的Series的处理。
applymap:只能用于DataFrame,用于处理该DataFrame的每个元素。
实例:将股票代码转换成中文名字
Series.map(dict)或者Serise.map(function)均可。
from ast import Lambda
import pandas as pd
path=r"C:\Users\radiomumm\Desktop\sucai\groupby\汇总.csv"
df=pd.read_csv(path,encoding="gbk")
print(df.head(20))
#查看名字列的内容
print(df["名字"].unique())
准备字典
dict_company_name={"BAIDU":"百度",
"BABA":"阿里巴巴",
"BILBIL":"哔哩哔哩",
"JINGDONG":"京东",
"NELFX":"奈飞"}
方法一:map函数传递一个dict
df['公司']=df["名字"].str.upper().map(dict_company_name)
print(df.head(20))
方法二:map函数传入一个函数【function的参数时series的每个元素值】
df['公司']=df["名字"].map(lambda x:dict_company_name[x.upper()])
print(df.head(20))
●Series.apply(function),函数的参数是series每个值,与series的map函数十分相似
df['公司']=df["名字"].apply(lambda x:dict_company_name[x.upper()])
print(df.head(20))
●DataFrame.apply(function),函数的参数是Series
df['公司']=df.apply(lambda x:dict_company_name[x["名字"].upper()],axis=1)
print(df.head(20))
【tips】:
apply是在Dataframe中调用;
Lambda的参数x是series,由于指定了asix=1所以Series的key是列名,可以用下x[“”]获取
实例:
将收盘、开盘、高、低、交易量的小数改为整数
sub_df=df[["收盘","开盘","高","低","交易量"]]
sub_df.loc[:,"交易量"]=df["交易量"].str.replace("M","").astype("float64")
sub_df.applymap(lambda x:int(x))
print(sub_df)
对原有Dataframe值进行批量修改
df.loc[:,["收盘","开盘","高","低","交易量"]]=sub_df.applymap(lambda x:int(x))
print(df)
补充:
1.Pandas的Groupby遵从三个模式,split、apply、combine模式。
事实上Split就是Pandas中的groupby,apply函数由我们自己控制,可以是一个内置函数也可以自己定义,apply返回值再由Pandas进行combine(拼接)获得输出结果。
2.归一化就是把数据经过处理后使之限定在一定的范围内。比如通常限制在区间[0, 1]或者[-1, 1]
groupby.apply(function)
1.怎样对数值列按分组进行归一化?
import pandas as pd
ratings=pd.read_csv(r"C:\Users\radiomumm\Desktop\sucai\ml-1m\ratings.dat",
sep="::",
engine="python",
names="User_id::Movie_id::Ratings::Timestamp".split("::"))
print(ratings.head())
def ratings_norm(df):
min_value=df["Ratings"].min()
max_value=df["Ratings"].max()
df["ratings_norm"]=df["Ratings"].apply(
lambda x:(x-min_value)/(max_value-min_value))
return df
ratings=ratings.groupby("User_id").apply(ratings_norm)
print(ratings[ratings["User_id"]==1].head())
16.1.2 怎样取每个分组的TOPN数据?
def get_topN(df,topn):
return df.sort_values(by="Ratings")[["User_id","Ratings"]][-topn:]
print(ratings.groupby("User_id",as_index=False E ).apply(get_topN,2).head(20))
左侧列表有利于数据增减,而右侧 数据利于数据处理和查找。
stack: DataFrame.stack(level=-1, dropna=True),将columh变成index,类似把横放的书籍变成竖放。
level=-1代表多层索引的最内层,可以通过==0、1、 2指定多层索引的对应层。
unstack: DataFrame.unstack(level=-1, fill value=None), 将index变成column,类似把竖放的书籍变成横放 。
pivot: DataFrame.pivot(index=None, columns=None, values=None),指定index、columns. values实现二维透视。
实例:统计得到"电影评分数据集",每个月份的每个分数被评分多少: (月份、 分数1~5、次数)
import pandas as pd
import numpy as np
df=pd.read_csv(r"C:\Users\radiomumm\Desktop\sucai\ml-1m\ratings.dat",
sep="::",
engine="python",
names="User_id::Movie_id::Ratings::Timestamp".split("::"))
对日期进行处理
df["pdata"]=pd.to_datetime(df["Timestamp"],unit="s")
# print(df.head(20))
实现数据统计,dt.month是按月份分组
df_groupby=df.groupby([df["pdata"].dt.month,"Ratings"])["User_id"].agg(pv=np.sum)
# print(df_groupby.head(20))
以上格式想要绘制横坐标为月份纵坐标为评分次数趋势是无法实现的,需要变化每个评分为一列才能实现
df_stack=df_groupby.unstack()
print(df_stack.head(20))
#绘图
import matplotlib.pyplot as plt
df_stack.plot()
plt.show()
#返回原有格式
df_unstack=df_stack.stack()
df_reset=df_groupby.reset_index()
# print(df_reset.head(20))
df_pivot=df_reset.pivot("pdata","Ratings","pv")#该方法与上文中的unstack相同
# print(df_pivot.head(20))