import pandas as pd
import numpy as py
s = pd.Sreies([1,3,5,npp.nan,44,1])
print (s)
data = pd.data_range('20170101',period=6)
df = DataFrame(np.random.randn(6,4),index=data,columns=['a','b','c','d'])
df = pd.DataFrame(np.arange(12),reshape(3,4)))
pf.columns 打印列名
df.index 打印行名
df. values 打印数值
df.describe() 描述数值型数据的平均值等属性
df.T 轴对称矩阵
df.sort_index(axis=0,ascending=False) 倒叙
(axis=1)
—values(by‘1’) 对1列的值进行排序
df['A'] df.A 取‘A’列
df[0:3] df['A':'B'] 去范围
通过标签选取
df.loc['A']
df.loc[,['A':'C']]
通过位置选取
df.iloc[3:5,1:2] 都是索引
df.iloc[[1,3,4],1:3]
混合选取
df.ix[:3,['A','D']
是否选取
df[dF.A<8]
选择数据并赋值
df.iloc[2,2]=111
df.loc['A',2]=222
df[df.A>4]=0 整个矩阵中A列大于4 的,都变成0
df.A[df.A>4]=0 A列中大于4 的都变成0
df.['F']= np.nan 增加一列F
df.['E']= pd.Series([1,2,3,4,5,6],index=dp.data_range('20170101',periob) 新增数据的值与列索引名称一致
处理空数据 nan数据
df.dropna(axis=0,how='any') # any 出现任意一个nan丢掉 all所有都是nan才丢掉
df.fillna(value=0) #用0填充nan
print(np.any(df.isnull()==Ture) #有任意一个nan都返回Ture
pandas数据读入与写出
pandas支持的数据类型 csv excel txt josn 等
data =pd.read_csv('student.csv') 数据的提取
pandas会给数据自动加上索引
data.to_pikle('student') 数据的写入
pandas数据的合并多个表
import numpy as np
import pandas as pd
df行向合并要求列数的属性一致
res=pd.concat([df1,df2,df3],axis=0,ignore_index=Ture) 忽略原来的索引从头开始排列
#join,['inner','outer']
当列项属性不一致时候
res=pd.concat([df1,df2],join='outer') 列项属性不一致是,集合所有属性,没有数据的用nan 填充 pandas默认选择
join='inner' 相同的列属性合并,不同的删除
join_axes=[df1.index] 一表1 为参照,表2 没有的属性nan填充,多余的属性删除
res=pd1.append(df2,axis=0,ignore=Ture)
([df2,df3])
s1=Series([1,2,3,4],index=['A','B','C','D'])
res=df1.append(s1,ignore_index=Ture)
res=pd.merge(df1,df2,on'key') 合并两表 昂拥有 共同的列属性时,以这个为key对两表进行合并
res.pd.merge(df1,df2,on['key1','key2'],how='inner') 合并有个两个共同的属性
how='outer'
how='df1'
indicator=Ture) 默认为Flase,Ture为显示怎样合并
res = pd.merge(left,right,left_index=Ture,righe_index=Ture,how='outer')
行向合并两组数据,两组数据的属性均为Ture,不改变,
res = pd.merge(boy,girl,on='k',suffixes=['boy_','girl_']) 合并拥有共同属性k的两个表,同样共同拥有的属性age,为了区分,加前缀
3.设置某列为索引
- 1
4.取出两列
- 1
5.将series变成list
- 1
- 2
6.将DataFrame变成ndarray类型
11.读取文件时,给数据指定新的列名称
- 1
12.重新命名df的列的名字
18.当所有列都是nan时被去掉,how的值, default=any
- 1
- 2
19.填充nan为特定数值
25.选出特定的行:选出标准差小于某一数的所有行,多个条件用&连接
- 1
26.将dataframe中的某一列转换成datetime类型
28.将多个Seies和dataframe join起来
- 1
29.计算同一个column相邻两个数字之间的变化率
- 1
30.替换DataFrame中的特定数值,例如:将数据中的所有的1和2都替换成3
32.将所有的列向下移动一格,index保持不变,第1行的数据用NaN代替
34.对DataFrame的字符串进行截取
- 1
35.每隔一定数据进行一次操作,例如:每隔10个数据进行一次func操作
- 1
36.去掉某些行
- 1
37.去掉某些列
- 1
38.将dataframe转array:
43.dataframe多条件选择数据
- 1
- 2
- 3
- 4
44.将某一列的数据进行转换:
- 1
45.切片操作
49.读取文件时指定某些列的数据类型:
- 1
50.判断某一列是否含有某字符:
10.过滤Series的值
通过布尔选择器(条件筛选)来过滤掉一些值,从而得到满足条件的值
s2[s2 < value]
s2[s2 > value]
s2[s2 == value]
s2[s2 != value]
#单条件筛选
s2[s2 > 90]
banana
aa 100
cc 120
Name: length, dtype: int64
s2[s2 == 13]
banana
dd 13
Name: length, dtype: int64
#多条件筛选
s2[(s2 > 50) | (s2 < 14)]
banana
aa 100
bb 11
cc 120
dd 13
Name: length, dtype: int64
11.Series的缺失值处理
#创建一个带有缺失值的Series
s = pd.Series([10,np.nan,15,19,None])
s
提示:None值会被当做NA处理
(1)判断是否有缺失值
isnull()
#判断s中的缺失值
s.isnull()
0 False
1 True
2 False
3 False
4 True
dtype: bool
#如果需要取出这些缺失值,则通过布尔选择器来筛选出来
s[s.isnull()]
1 NaN
4 NaN
dtype: float64
(2)删除缺失值
dropna()
#dropna()会删除掉所有缺失值NaN,并返回一个新的Series
s.dropna()
0 10.0
2 15.0
3 19.0
dtype: float64
#原有的Series并未发生改变
s
0 10.0
1 NaN
2 15.0
3 19.0
4 NaN
dtype: float64
#如果希望原有的Series发生改变,可以将s.dropna()返回的新Series直接赋值给原来的Series
s = s.dropna()
s
0 10.0
2 15.0
3 19.0
dtype: float64
此外,我们也可以通过过滤的方式来达到一样的删除效果:
data[~data.isnull()]
data[data.notnull()]
s = pd.Series([10,np.nan,15,19,None]) #初始化一下s
s[~s.isnull()] #依然是返回一个新的Series,波浪号~表示否定、非的意思
0 10.0
2 15.0
3 19.0
dtype: float64
#通过notnull()也能实现,同样也是返回一个新的Series
s[s.notnull()]
0 10.0
2 15.0
3 19.0
dtype: float64
(3)填充缺失值
fillna()
用指定值或插值的方式填充缺失值
- 用指定值填充缺失值
#用0填充缺失值,返回的依然是一个新的Series
s.fillna(value=0)
0 10.0
1 0.0
2 15.0
3 19.0
4 0.0
dtype: float64
#如果希望直接修改原Series,一种方法是之前说的直接赋值,另一种是添加参数inplace=True
s.fillna(value=0,inplace=True)
- 用插值填充缺失值
#初始化一下s
s = pd.Series([10,np.nan,15,19,None])
s
向前填充(ffill,全称是front fill)
s.fillna(method="ffill")
0 10.0
1 10.0
2 15.0
3 19.0
4 19.0
dtype: float64
向后填充(bfill,全称是back fill)
s.fillna(method="bfill")
0 10.0
1 15.0
2 15.0
3 19.0
4 NaN
dtype: float64
12.排序
#创建一个Series
s3 = pd.Series([10,15,8,4,20],index=list("gadkb"))
s3
g 10
a 15
d 8
k 4
b 20
dtype: int64
(1)根据索引排序
sort_index() 默认升序,如果添加参数ascending=False,则降序排列
#根据索引升序排列
s3.sort_index()
a 15
b 20
d 8
g 10
k 4
dtype: int64
#根据索引降序排列
s3.sort_index(ascending=False)
k 4
g 10
d 8
b 20
a 15
dtype: int64
(2)根据值排序
sort_values() 默认升序,如果添加参数ascending=False,则降序排列
#根据值升序排列
s3.sort_values()
k 4
d 8
g 10
a 15
b 20
dtype: int64
#根据值降序排列
s3.sort_values(ascending=False)
b 20
a 15
g 10
d 8
k 4
dtype: int64
13.排名
rank()
#创建一个用来排名的Series
s4 = pd.Series([2,5,15,7,1,2])
s4
0 2
1 5
2 15
3 7
4 1
5 2
dtype: int64
中国式排名
s4.rank(ascending=False,method="dense")
0 4.0
1 3.0
2 1.0
3 2.0
4 5.0
5 4.0
dtype: float64
14.Series的描述性统计
#创建一个Series
s5 = pd.Series([100,50,100,75,24,100])
s5
- 值的计数 Series.value_counts()
s5.value_counts()
100 3
75 1
50 1
24 1
dtype: int64
- 最小值 s5.min()
s5.min()
24
- 最大值 s5.max()
s5.max()
100
- 中位数 s5.median()
s5.median()
87.5
- 均值 s5.mean()
s5.mean()
74.83333333333333
- 求和 s5.sum()
s5.sum()
449
- 标准差 s5.std()
s5.std()
31.940048006643114
- 描述性统计 s5.describe()
s5.describe().round(1)
count 6.0
mean 74.8
std 31.9
min 24.0
25% 56.2
50% 87.5
75% 100.0
max 100.0
dtype: float64
15.Series的向量化运算
可对Series进行批量操作,并且返回一个新的Series,并不会在原基础上直接修改
s5 + 1000
0 1100
1 1050
2 1100
3 1075
4 1024
5 1100
dtype: int64
s5 - 2000
0 -1900
1 -1950
2 -1900
3 -1925
4 -1976
5 -1900
dtype: int64
s5 * 2
0 200
1 100
2 200
3 150
4 48
5 200
dtype: int64
s5 / 10
0 10.0
1 5.0
2 10.0
3 7.5
4 2.4
5 10.0
dtype: float64
自动对齐相同索引的数据,不同索引的数据对不上,则显示NaN
s6 = pd.Series([35000,40000,71000,5500],index=list("abcd"))
s7 = pd.Series([222,35000,4000,2222],index=list(aqtb))
s6 + s7
a 35222.0
b 42222.0
c NaN
d NaN
q NaN
t NaN
dtype: float64
DataFrame——数据检查
阿雷边学边教python数据分析第3期——pandas与numpy
数据表通常较大,无法一目了然地看清数据的整体概况,因此我们需要通过一些方法来获得数据的整体信息,好对数据表有个整体的了解。
示例文件:
import pandas as pd
import numpy as np
df = pd.read_csv("pokemon_data.csv",encoding="gbk")
1.查看前5行和后5行
df.head()
df.head(10)
df.tail()
df.tail(8)
2.查看列名
df.columns
3.查看索引
df.index
4.查看行列数
df.shape
5.查看数据格式
-
数据表中所有的数据类型
df.dtypes -
某一列的数据类型
df["Name"].dtypes
6.查看空值
df.isnull()
显示True的就是空值,也即是缺失值
7.查看数据表信息
df.info()
8.查看唯一值
df["Name"].unique()
DataFrame——数据清洗
阿雷边学边教python数据分析第3期——pandas与numpy
#导入pandas库和numpy库
import pandas as pd
import numpy as np
1.缺失值处理
python中用NaN(Not a Number)表示缺失数据
#示例数据
df = pd.read_csv("pokemon_data.csv",encoding="gbk")
#查看数据前十行
df.head(10)
(1)判断缺失值
df.isnull() #判断数据表所有数据的缺失值
df["类型2"].isnull() #判断数据表某一列的缺失值
#查看类型2这一列的非缺失值和缺失值的数量分布
df["类型2"].isnull().value_counts()
(2)删除缺失值
df.dropna() #删除掉含有缺失值的所有行
df.dropna(how="any") #删除掉含有缺失值的所有行
df.dropna()等价于df.dropna(how="any")
df.dropna(how="all") #删除满足行内数据均为NaN这个条件的行
#创建一个4行3列的含有NaN的数据作为演示
df1 = pd.DataFrame([[1,5,np.nan],[2,np.nan,np.nan],[2,3,np.nan],[np.nan,np.nan,np.nan]])
df1
#how="all"能删除掉均为NaN的行
df1.dropna(how="all")
#删除满足列内数据均为NaN这个条件的列,按列删除
df1.dropna(how="all",axis=1)
(3)填充缺失值
# 示例数据
df1 = pd.DataFrame([[1,5,np.nan],[2,np.nan,np.nan],[2,3,np.nan],[np.nan,np.nan,np.nan]])
- 填充指定值
df1.fillna(value=0)
- 填充函数
#对第2列的缺失值,用该列的均值填充
df1[1].fillna(df1[1].mean())
- 向前填充
#对第2列的缺失值进行向前填充
df1[1].fillna(method="ffill")
- 向后填充
#对第2列的缺失值进行向后填充
df1[1].fillna(method="bfill")
2.清除空格
#创建含有空格的数据
dict1 = {"name":["小红","小明","小张"],"age":[16,17,18],"city":["北京 ","杭州"," 上海 "]}
df2 = pd.DataFrame(dict1,columns=["name","age","city"])
#清除空格
df2["city"]=df2["city"].map(str.strip)
3.转换数据格式
df2["age"]=df2["age"].astype("str") #转换成字符串格式
df2["age"]=df2["age"].astype("float") #转换成浮点数格式
df2["age"]=df2["age"].astype("int") #转换成整数格式
4.大小写转换
df2["city"]=df2["city"].str.lower() #转换成全小写
df2["city"]=df2["city"].str.upper() #转换成全大写
df2["city"]=df2["city"].str.title() #转换成首字母大写
5.更改列名
#通过rename函数修改部分列名或者所有列名,并默认返回一个新的数据框,若需要在原基础上修改,添加参数inplace=True即可
df2.rename(columns={"name":"name2","age":"age2"})
#通过columns属性修改列名,这种方式就需要输入所有的列名了,并直接在原基础上修改
df2.columns = ["n","a","c"]
6.更改索引与重置索引
(1)更改索引
set_index()
df.set_index("类型1")
(2)重置索引
reset_index()
df.reset_index()
7.重复值处理
#示例数据
df5 = pd.DataFrame({"c1":["apple"]*3 + ["banana"]*3,"c2":[1,1,2,3,3,2]})
(1)查看是否有重复值
#适合小数据目测
df5.duplicated(subset=["c1","c2"],keep="first")
#当数据量比较大的时候,可以看看重复数据和非重复数据的计数分布
df5_duplicated = df5.duplicated(subset=["c1","c2"],keep="first")
df5_duplicated.value_counts()
(2)保留重复值
df5[df5.duplicated(subset=["c1","c2"],keep="first")]
(3)删除重复值
#默认保留第一个出现的重复值,删除掉后面的重复值
df5.drop_duplicates(subset=["c1","c2"],keep="first")
#保留最后一个重复值,删除掉前面的重复值
df5.drop_duplicates(subset=["c1","c2"],keep="last")
#如果希望直接在原基础上修改,添加参数inplace=True
df5.drop_duplicates(subset=["c1","c2"],keep="last",inplace=True)
8.替换值
#示例数据
df6 = df.head(10)
#忽略警告
import warnings
warnings.filterwarnings("ignore")
(1)单一对象替换单个值
df["colname"].replace("替换对象","替换值")
df6["类型1"] = df6["类型1"].replace("Grass","G")
(2)多对象替换单个值
df["colname"].replace(["替换对象1","替换对象2",...],"替换值")
df6["类型1"] = df6["类型1"].replace(["G","Fire"],"gf")
(3)用不同的值替换不同的对象
df["colname"].replace(["替换对象1","替换对象2",...],["替换值1","替换值2",...])
df6["类型1"] = df6["类型1"].replace(["gf","Water"],["good","W"])
(4)参数也可以是字典
df["colname"].replace({"替换对象1":替换值1,"替换对象2":替换值2,...})
df6["类型1"] = df6["类型1"].replace({"good":"gg","W":"ww"})
DataFrame—数据处理
阿雷边学边教python数据分析第3期——pandas与numpy
一.数据的增删改
1.增加行
(1)手动输入新增行的内容
#示例数据:
df1 = pd.DataFrame({"name":["ray","jack","lucy","bob","candy"],
"city":["hangzhou","beijing","hangzhou","chengdu","suzhou"],
"score":[10,30,20,15,50]},
columns=["name","city","score"])
df1.loc[5] = ["baby","shanghai",80]
(2)将同字段的DataFrame添加进来
#示例数据:
df1 = pd.DataFrame({"name":["ray","jack","lucy","bob","candy"],
"city":["hangzhou","beijing","hangzhou","chengdu","suzhou"],
"score":[10,30,20,15,50]},
columns=["name","city","score"])
df1_1 = pd.DataFrame({"name":["faker","lucy"],
"city":["guangzhou","shenzhen"],
"score":[70,75]},
columns=["name","city","score"])
#append做法
df1.append(df1_1,ignore_index=True)
#concat做法
pd.concat([df1,df1_1],ignore_index=True)
2.删除行
#示例数据:
df_concat = pd.concat([df1,df1_1],ignore_index=True)
#删除第7行,也即是索引号为6的这一行
df_concat.drop(6)
#删除第4行和第6行
df_concat.drop([3,5])
通过drop我们可以删除掉不需要的特定行,但其实更多的时候我们可能只需要直接筛选需要的行或者过滤掉一些不需要的行即可,关于如何选择和过滤在下期会详细讲。
3.修改行
若要修改行,则要先选出需要修改的一行或多行,再重新赋值
#示例数据
df1 = pd.DataFrame({"name":["ray","jack","lucy","bob","candy"],
"city":["hangzhou","beijing","hangzhou","chengdu","suzhou"],
"score":[10,30,20,15,50]},
columns=["name","city","score"])
#将第一行的ray修改成demon,hangzhou改成wenzhou,10改成35
df1.loc[0] = ["demon","hangzhou",35]
#多行修改
df1.loc[0:2] = [["d","j","l"],["h","b","h"],[40,50,60]]
4.增加列
(1)在末尾插入列
DataFrame["new coloum name"] = value
#示例数据
df1 = pd.DataFrame({"name":["ray","jack","lucy","bob","candy"],
"city":["hangzhou","beijing","hangzhou","chengdu","suzhou"],
"score":[10,30,20,15,50]},
columns=["name","city","score"])
#末尾增加一列:gender(性别)
df1["gender"] = ["male","male","female","male","female"]
(2)在任意位置插入新列
DataFrame.insert(index,"new coloum name",value)
#在第2列的位置插入新的一列:height(身高)
df1.insert(1,"height",[170,165,172,180,169])
#第1个参数表示索引号即插入的位置,第2个参数填列的名称,第3个参数填值
5.删除列
#示例数据
df1 = pd.DataFrame({"name":["ray","jack","lucy","bob","candy"],
"city":["hangzhou","beijing","hangzhou","chengdu","suzhou"],
"score":[10,30,20,15,50]},
columns=["name","city","score"])
(1)del DataFrame["colname"]
删除特定行,并且直接从原DataFrame中修改过来
#删除score列
del df1["score"]
(2)DataFrame.drop(["colname"],axis = 1)
axis=1表示按列删除,默认是返回一个新的DataFrame,如果需要直接修改原DataFrame,则添加参数inplace=True,如果要删除多列,则在方括号[]内继续添加列名,如果只需要删除单列,方括号[]可加可不加
#删除city列
df1.drop(["city"],axis=1)
6.修改列
若要修改列,则要先选出需要修改的一列或多列,再重新赋值
#示例数据
df1 = pd.DataFrame({"name":["ray","jack","lucy","bob","candy"],
"city":["hangzhou","beijing","hangzhou","chengdu","suzhou"],
"score":[10,30,20,15,50]},
columns=["name","city","score"])
#修改score列
df1["score"] = 50
#修改city和score列
df1[["city","score"]] = [["hz","bj","hz","cd","sz"],60]
二.数据集的合并
merge
Q1:什么是merge?
通过一个键或多个键将不同的DataFrame中的行连接起来
Q2:如何merge?(连接方式)
1.将列作为键来合并
#示例数据:
df1 = pd.DataFrame({"name":["ray","jack","lucy","bob","candy"],
"city":["hangzhou","beijing","hangzhou","chengdu","suzhou"],
"score":[10,30,20,15,50]},
columns=["name","city","score"])
df2 = pd.DataFrame({"name":["ray","lucy","demon"],
"age":[15,17,16]},
columns=["name","age"])
(1)inner连接(交集)
pd.merge(df1,df2,on="name",how="inner")
只保留df1和df2公有的name,以及这些name对应的其他列
这种写法等价于
pd.merge(df1,df2)
因为merge在没有指定某列作为键的情况下,会默认将重叠列的列名作为键,即name列作为键;且默认的连接方式是inner。
(2)outer连接(并集)
pd.merge(df1,df2,on="name",how="outer")
保留df1和df2所有的name,以及name对应的其他列,name匹配不到的列值显示NaN
(3)left连接(保左加右)
pd.merge(df1,df2,on="name",how="left")
保留左边的数据集df1的所有列,用df1的name去匹配df2的name,把df2中能匹配得上的name所对应的其他列都加进来。换言之,也即是在df1的基础上加上df2中能够匹配的数据,不能匹配的数据舍弃掉。简而言之就是保左加右。
(4)right连接(保右加左)
pd.merge(df1,df2,on="name",how="right")
和left连接的原理一样,保留右边的数据即第二个参数df2,在这个基础上加上左边能匹配上的数据即可。
一些可能遇到的问题:
Q1:如果两个数据指定列的列名不一样怎么办?
比如创建一个df3,和df2数据一样,只是name列名改成name2:
df3 = df2.rename(columns={"name":"name2"})
现在需要按照df1的name列和df3的name2列来进行合并
pd.merge(df1,df3,left_on="name",right_on="name2",how="inner")
Q2:如果需要多个键来进行合并怎么办呢?
先修改下源数据df1和df2
df1.loc[5] = ["ray","wuhan",80] #给df1增加新的一行,名称为已出现的ray
df2["city"] = ["hangzhou","hangzhou","heilongjiang"] #给df2增加新的一列city
如果只用name来作为键来匹配是无法成功的,因为有2个ray,他们是同名的不同人,所以需要更多的约束条件来精确匹配,用name和city这两列共同作为键来精确匹配:
pd.merge(df1,df2,on=["name","city"],how="left")
2.将索引作为键来合并
#示例数据
left1 = pd.DataFrame({"key":list("acba"),"value":range(4)})
right1 = pd.DataFrame({"value2":[10,20]},index=["a","b"])
合并left1和right1的交集,通过left1的"key"列和right1的索引列作为键来合并
pd.merge(left1,right1,left_on="key",right_index=True,how="inner")
三.数据的轴向连接
concat
axis=0:表示在横轴上工作,所谓横轴也即是行,而行的方向是上下,因此你可以理解为在上下方向执行操作
axis=1:表示在纵轴上工作,所谓纵轴也即是列,而列的方向是左右,因此你可以理解为在左右方向直行操作
那么数据的轴向连接也就是指:当axis=0时,将两份或多份数据按照上下方向拼接起来;当axis=1时,将两份或多份数据按照左右方向拼接起来。
(1)横轴上的连接,axis=0时(concat默认axis=0)
- 两份数据的列名完全相同的情况:
#示例数据
df1 = pd.DataFrame({"name":["ray","jack","lucy","bob","candy"],
"city":["hangzhou","beijing","hangzhou","chengdu","suzhou"],
"score":[10,30,20,15,50]},
columns=["name","city","score"])
df2 = pd.DataFrame({"name":["faker","fizz"],
"city":["wenzhou","shanghai"],
"score":[55,80]},
columns=["name","city","score"])
#按横轴连接df1和df2
pd.concat([df1,df2],ignore_index=True)
- 两份数据的列名存在不同的情况下:
#示例数据
df1 = pd.DataFrame({"name":["ray","jack","lucy","bob","candy"],
"city":["hangzhou","beijing","hangzhou","chengdu","suzhou"],
"score":[10,30,20,15,50]},
columns=["name","city","score"])
df2 = pd.DataFrame({"name":["faker","fizz"],
"city":["wenzhou","shanghai"],
"gender":["male","female"]},
columns=["name","city","gender"])
#按横轴连接df1和df2
pd.concat([df1,df2],ignore_index=True)
#会得到这两份数据的并集,没有的值会以NaN的方式填充
- 在连接轴上创建一个层次化索引
df_concat = pd.concat([df1,df2],keys=["df1","df2"])
(2)纵轴上的连接,axis=1时
#按纵轴方向合并df1和df2
pd.concat([df1,df2],axis=1)
四.合并重叠数据
combine_first
#示例数据
data1 = pd.DataFrame({"score":[60,np.nan,75,80],
"level":[np.nan,"a",np.nan,"f"],
"cost":[1000,1500,np.nan,1200]})
data2 = pd.DataFrame({"score":[34,58,np.nan],
"level":[np.nan,"c","s"]})
data1.combine_first(data2)
data1和data2有索引重叠的部分:即level列和score列的前三行。那么对于data1中的数据,如果data1已有数据,则继续用data1的数据,如果data1中有缺失数据,那么对于缺失数据用参数里的对象data2中的对应值来补充
五.数据分组
示例数据:
df = pd.read_csv("pokemon_data.csv",encoding="gbk")
- Q1:攻击力大于或等于79的划分为强攻,攻击力小于79的划分为弱攻
- Q2:满足攻击力大于或等于79,且防御力大于或等于100,划分为S级,其余的划分为A级
1.np.where
#Q1
df["攻击强弱度"] = np.where(df["攻击力"] >= 79,"强攻","弱攻")
#Q2
df["划分级"] = np.where((df["攻击力"] >= 79) & (df["防御力"] >= 100),"S级" ,"A级")
2.loc
#Q1
df.loc[df["攻击力"] >= 79,"攻击强弱度"] = "强攻"
df.loc[df["攻击力"] < 79,"攻击强弱度"] = "弱攻"
#Q2
df.loc[(df["攻击力"] >=79) & (df["防御力"] >=100),"划分级"] = "S级"
df.loc[~((df["攻击力"] >=79) & (df["防御力"] >=100)),"划分级"] = "A级"
np.where和loc分组的区别:
如果你想按照条件判断分两组,那么就使用np.where
如果你想按照条件判断分为多个组,就使用loc
六.数据分列与合并
1.分列
split
#示例数据
df4 = pd.DataFrame({"name":["ray","jack","lucy","bob","candy"],
"h&w":["175-70","180-80","168-74","177-72","182-90"],
"score":[10,30,20,15,50]},
columns=["name","h&w","score"])
需求:现在需要将h&w这一列的数据拆分开,分为身高列和体重列,并且拆分后的列需要在源数据里呈现出来
#对h&w列的值依次进行分列,并创建数据表df_split,索引值为df4的索引,列名位height和weight
df_split = pd.DataFrame([x.split("-") for x in df4["h&w"]],index=df4.index,columns=["height","weight"])
#将分列后的数据表df_split与原df4数据表进行匹配
df4 = pd.merge(df4,df_split,right_index=True,left_index=True)
2.合并
需求:现在需要将name和score合并为一列,形式如ray:10,合并后的新列需要在源数据里呈现出来
df4["name:score"] = df4["name"] + ":" + df4["score"].apply(str)
apply可以将一个函数用于DataFrame的所有行或者所有列,也可以应用在DataFrame的一行或者是一列。
七.排序
#示例数据
df = pd.read_csv("pokemon_data.csv",encoding="gbk")
1.根据值排序
sort_values
(1)升序排列(由小到大)
df.sort_values(by="总计") #默认就是升序排列
(2)降序排列(由大到小)
df.sort_values(by="总计",ascending=False) #添加ascending=False参数来降序排列
(3)多级关键词排序
#如果都做升序排列
df.sort_values(by=["总计","攻击力"])
#如果都做降序排列
df.sort_values(by=["总计","攻击力"],ascending=False)
#如果按照总计列做升序排列,但是总计相等的行按照攻击力做降序排列
df.sort_values(by=["总计","攻击力"],ascending=[True,False])
(4)如果希望直接在修改源数据的基础上进行排序,添加参数inplace=True即可
#以升序排列为例
df.sort_values(by="总计",inplace=True)
2.根据索引排序
sort_index
(1)升序排列
df.sort_index(inplace=True)
(2)降序排列
df.sort_index(ascending=False,inplace=True)
八.排名
rank
#示例数据
df = pd.read_csv("pokemon_data.csv",encoding="gbk")
df_rank = df.head(10)
做个中国式排名:希望通过总计列的大小进行排名,并新增一个排名列,值大的排名靠前,值小的排名靠后,如果值一样则占同一个排名位,排名位是连续的,不存在间断。
df_rank["rank"] = df_rank["总计"].rank(ascending=False,method="dense")
九.转置
T
#示例数据
df5 = pd.DataFrame({"cost":[800,1000,1200],"sale":[1000,2000,2500]},index=["1月","2月","3月"])
#行索引和列索引进行转置
df5 = df5.T
df5
DataFrame——数据选取与筛选
阿雷边学边教python数据分析第3期——pandas与numpy
一.数据选取
- 按索引标签选取(loc做法)
- 按索引位置选取(iloc做法)
Q1:选取第1行的数据(选取单行数据)
(1)按索引标签选取(loc做法)
df.loc[0] #返回的是Series
df.loc[[0]] #如果在里面多加一个方括号,那么返回的是DataFrame
(2)按索引位置选取(iloc做法)
df.iloc[0] #返回的是Series
df.iloc[[0]] #如果在里面多加一个方括号,那么返回的是DataFrame
问题来了:为什么在这里loc和iloc得到的结果是一样的?
下面会解释
Q2:选取第2到第5行的数据(选取连续行的数据)
(1)按索引标签选取(loc做法)
df.loc[1:4]
你可能产生了一个疑问:不是说切片的末端是取不到的吗,也就是4这个索引所指向的第5行应该是取不到的
这是因为loc是按照索引标签来选取数据的,而不是根据位置来选取,举个例子:
#以姓名这一列作为行索引
df_name = df.set_index("姓名")
df_name
如果我要返回第2行到第5行的数据,该怎么做呢?
df_name.loc[1:4] #如果按照刚刚的写法,就会出错
#因为loc是按照索引标签选取的,按照下面这种写法就对了
df_name.loc["Ivysaur":"Charmander"]
所以说,之前写的df.loc[1:4]能返回第2到第5行的数据,只是恰好因为索引号是默认生成的数字索引,1对应的就是第2行的索引,4对应的是第5行的索引,1:4代表的是从第2行到第5行的索引标签,本质是和现在的"Ivysaur":"Charmander"一样的,都是代表索引标签,而不是位置。所以按照这种索引标签来选取数据的方法是能够取到末端的数据的.现在回去看刚刚Q1的问题你就明白了为什么在Q1里loc和iloc得到的结果是一样的,因为df数据的索引标签和位置恰好一样。
(2)按索引位置选取(iloc做法)
df.iloc[1:5]
我们需要返回的是第2行到第5行,因此对应的索引位置是1:4,但是由于iloc是按照位置来选取数据的,遵循左闭右开的原则,因此末端索引是取不到的,那么末端就需要再加1,这样就能确保第5行能取到了,而取不到第6行
为了能更直观地体现出loc和iloc的区别,接下来以df_name为示例数据
#示例数据
df_name
Q3:选取第2行,第4行,第7行,第10行的数据(选取特定行的数据)
(1)按索引标签选取(loc做法)
df_name.loc[["Ivysaur","VenusaurMega Venusaur","Charizard","Squirtle"]]
(2)按索引位置选取(iloc做法)
df_name.iloc[[1,3,6,9]]
Q4:选取攻击力列(选取单列的数据)
(1)直接方括号+列名
#直接方括号输入列名即可,推荐这种方法
df_name["攻击力"]
#返回的是一个Series
df_name[["攻击力"]]
#返回的是一个DataFrame
(2)按索引标签选取(loc做法)
#虽然用loc也能提取单列,但是显得不够简洁
df_name.loc[:,["攻击力"]]
(3)按索引位置选取(iloc做法)
df_name.iloc[:,[4]]
(4)点号选取法
#也可以通过点号选取列
df_name.攻击力
点号提取列的这种方法的优点是:写法比较简洁快速,缺点是如果列名和关键字重复了就无法提取了,因为点号调用的是对象,python无法判断出名字一样的列名和关键字
#举个例子说明,新增一列class,值为1
df_name["class"] = 1
df_name
df_name.class
#由于class是python的关键字,而点号选取列实质上是在调用对象,本身列名class和关键字class重叠了,导致无法调用成功
Q5:选取类型1列到攻击力列的所有数据(选取连续列的数据)
(1)按索引标签选取(loc做法)
df_name.loc[:,"类型1":"攻击力"]
(2)按索引位置选取(iloc做法)
df_name.iloc[:,:4]
Q6:选取“类型2”列,攻击力列,防御力列的所有数据(选取特定列的数据)
(1)方括号+列名
#用方括号+列名来直接提取,这种方式比较简洁
df_name[["类型2","攻击力","防御力"]]
(2)按索引标签选取(loc做法)
df_name.loc[:,["类型2","攻击力","防御力"]]
(3)按索引位置选取(iloc做法)
df_name.iloc[:,[1,4,5]]
Q7:选取第3行到第8行,类型1列到攻击力列(选取部分行部分列的数据)
(1)按索引标签选取(loc做法)
df_name.loc["Venusaur":"CharizardMega Charizard X","类型1":"攻击力"]
(2)按索引位置选取(iloc做法)
df_name.iloc[2:7,:5]
拓展:ix选取数据的做法
也许有的人觉得一会索引标签来选取,一会索引位置来选取,记起来好麻烦,那么,有没有一种万能的办法呢?
确实有种相对较万能的办法,就是 ix,它既能够按照索引标签选取数据,也能够按照索引位置选取数据
ix的工作原理:根据索引的类型分2种情况:
1.索引为整数标签,那么按照索引标签选取行数据,不能按照索引位置选取行数据,列数据既能通过标签选取也能通过位置选取。
2.当索引为非整数标签(如字符串标签),那么可以用索引标签选取行数据,也可以按照索引位置选取行数据,列数据既能通过标签选取也能通过位置选取。
个人建议:还是使用loc和iloc来选取数据较好,因为分工明确,loc通过索引标签选取数据,iloc通过索引位置选取数据,所以你会很清除地知道你是在索引标签上操作还是在索引位置上操作,不会觉得混乱。我并不是特别建议使用ix,ix会让你觉得很混乱,也会让别人看你的代码时会在想:到底现在是在索引标签上操作还是位置上操作?这就增加了一个判断的过程。
二.数据筛选
#示例数据
df.head()
Q1:选取出攻击力大于100的所有数据
1.loc筛选
df.loc[df["攻击力"] > 100]
2.query筛选
df.query("攻击力 > 100")
Q2:选出攻击力大于100且防御力大于100的数据,并且列只要姓名、攻击力、防御力
1.loc筛选
df.loc[(df["攻击力"] > 100) & (df["防御力"] > 100),["姓名","攻击力","防御力"]]
2.query筛选
df.query("攻击力 > 100 & 防御力 > 100")[["姓名","攻击力","防御力"]]
Q3:选出类型1为Grass的所有数据
1.loc筛选
#做法1
df.loc[df["类型1"] == "Grass"]
#做法2
df.loc[df["类型1"].isin(["Grass"])]
2.query筛选
df.query("类型1 == 'Grass'")
loc筛选和query筛选的区别:
1.query的写法更简洁,免去了写数据框名称的步骤,节省时间
2.query不能引入变量,loc可以引入变量
三.多重索引
Q1:什么是多重索引
指2层或2层以上的索引
为什么会用到多重索引呢?
因为有时候需要通过多个维度来查看数据
Q2:如何创建多重索引
通过set_index([第一层索引,第二层索引,...])的方式创建含有多重索引的数据
#当我们要以字符串列作为索引列时,要保证这列为字符串格式
df[["类型1","类型2"]] = df[["类型1","类型2"]].astype("str")
#创建一个具有2重索引的数据作示例
df_pokemon = df.set_index(["类型1","类型2"])
df_pokemon
参数介绍:
drop:是指该列被指定为索引后,是否删除该列,默认为True,即删除该列。如果改成False,则多重索引在数据集的列中也会保留
append:指定是否保留原索引,默认为False,即不保留,如果改成True,则保留原索引
inplace:指是否在源数据的基础上修改,默认为False,即不修改,返回一个新的数据框,如果改成True,则直接在源数据上修改
level介绍:
#获取第一层索引
df_pokemon.index.get_level_values(0)
#获取第二层索引
df_pokemon.index.get_level_values(1)
#交换level
df_pokemon.swaplevel()
Q3:如何通过多重索引选取数据
1.先对索引进行升序排序
df_pokemon.sort_index(inplace=True)
为什么要对索引升序排序?
因为如果没有对索引进行升序排序的话,在多重索引选取数据的过程中无法通过切片选取数据,切片是由小到大取的,例如字符串a→z,数字0→100,所以在对索引进行升序后,才能正确地切片选取数据
2.用loc通过多重索引选取数据
#取出第一索引列中值为Bug的所有数据
df_pokemon.loc["Bug"]
#取出第一索引列为Bug,第二索引列为Poison的所有数据
df_pokemon.loc[("Bug","Poison")]
#选出第一索引列为Bug到Grass的所有数据
df_pokemon.loc[slice("Bug","Grass")]
#选出第一索引列为Bug到Grass,且第二索引列为Electric的所有数据
df_pokemon.loc[(slice("Bug","Grass"),"Electric"),:]
当想要取某一列索引下的全部数据时就需要用slice(None)
#取第二索引列为Electric的所有数据
df_pokemon.loc[(slice(None),"Electric"),:]
#取第二索引列为Electric和Fire,且列为姓名到攻击力的所有数据
df_pokemon.loc[(slice(None),["Electric","Fire"]),"姓名":"攻击力"]
前面的做法有一点繁琐,还有更简洁的做法,可以不用去写slice
idx = pd.IndexSlice
#取第二索引列为Electric和Fire,且列为姓名到攻击力的所有数据
df_pokemon.loc[idx[:,["Electric","Fire"]],"姓名":"攻击力"]
#取第二索引为Electric到Fire的所有数据
df_pokemon.loc[idx[:,"Electric":"Fire"],:]
#取第一索引为Bug到Grass,且第二索引为Electric到Fire的所有数据
df_pokemon.loc[idx["Bug":"Grass","Electric":"Fire"],:]
还有一个函数xs可以通过level指定索引,然后去选取数据
#选取第一索引列即类型1为Bug的所有数据
df_pokemon.xs("Bug",level=0)
#选取第二索引列为Electric的所有数据
df_pokemon.xs("Electric",level=1)
#选取第二索引列为Electric的所有数据,并且保留第二索引列
df_pokemon.xs("Electric",level=1,drop_level=False)
#选取第一索引列为Bug和Dark,第二索引列为Electric和Fire的所有数据
df_pokemon.xs(("Bug","Electric"),level=(0,1))
#level也可以是索引列名
df_pokemon.xs(("Bug","Electric"),level=(["类型1","类型2"]))
xs在每个索引列上选择的标签只能是一个,所以做不到切片标签的选取
DataFrame——数据汇总
阿雷边学边教python数据分析第3期——pandas与numpy
一.分组计算
1.什么是分组计算?
以宠物小精灵数据集为例
#示例数据
df = pd.read_csv("pokemon_data.csv",encoding="gbk")
小精灵会有多个分类,例如有火系的(Fire),或者是草系的(Grass)等等,那么分组计算就是指:将不同类别的小精灵归入到不同的组,例如火系的归一组,草系的归一组,这样我们就得到了很多个组,然后对这些组可以去实现不同的计算,例如求每一个组攻击力的平均值,这样我们就得到了每一个组它们自身组内的攻击力均值了。
2.如何分组计算?
分组计算用到的一个重要函数就是groupby
groupby分组计算流程:split——apply——combine
(1)split(拆分)
根据键对数据进行分组,常见的键类型有两种
- 根据列来分组
- 根据索引来分组
(2)apply(应用)
对每个组应用函数,类型有三种
- aggregation:聚合,对每个组计算统计值
- transformation:转换,对每个组进行特殊计算,例如在组内标准化数据
- filtration:过滤,对组进行条件过滤,根据条件判断得到的布尔值,丢弃掉一些组
(3)combine(合并)
将计算好的组整合到一个数据结构中
实例演练:
Q1:想知道类型1的这18个种类各自的平均攻击力是多少(单列分组计算)
#根据类型1这列来分组,并将结果存储在grouped1中
grouped1 = df.groupby("类型1")
#求类型1的18个种类各自的平均攻击力
grouped1[["攻击力"]].mean()
小结一下:
grouped1 = df.groupby("类型1")
这一步就是分组计算流程里的第一步:split(通过类型1这列对数据进行了分组)grouped1[["攻击力"]].mean()
这一步就是分组计算流程的第二和第三步:apply(对每个组应用函数mean)—combine(将结果整合到了一个新的DataFrame里)
Q2:想知道类型1和类型2的组合类型里,每个组合各自的攻击力均值(多列分组计算)
grouped2 = df.groupby(["类型1","类型2"])
grouped2[["攻击力"]].mean()
Q3:想知道类型1和类型2的组合类型里,每个组合各自的攻击力均值、中位数、总和(对组应用多个函数)
grouped2[["攻击力"]].agg([np.mean,np.median,np.sum])
Q4:想知道类型1和类型2的组合类型里,每个组合各自的攻击力的均值和中位数,生命值的总和(对不同列应用不同的函数)
grouped2.agg({"攻击力":[np.mean,np.median],"生命值":np.sum})
Q5:对组内数据进行标准化处理(转换)
zscore = lambda x : (x-x.mean())/x.std()
grouped1.transform(zscore)
Q6:对组进行条件过滤(过滤)
需求:针对grouped2的这个分组,希望得到平均攻击力为100以上的组,其余的组过滤掉
attack_filter = lambda x : x["攻击力"].mean() > 100
grouped2.filter(attack_filter)
Q7:将类型1和2作为索引列,按照索引来实现分组计算(根据索引来分组计算)
#将类型1、类型2设置为索引列
df_pokemon = df.set_index(["类型1","类型2"])
#根据索引分组
grouped3 = df_pokemon.groupby(level=[0,1])
#分组计算各列均值
grouped3.mean()
3.组的一些特征
group.size()可以查看每个索引组的个数
grouped2.size()
group.groups 可以查看每个索引组的在源数据中的索引位置
grouped2.groups
group.get_group((索引组)) 得到包含索引组的所有数据
#得到索引组为Fire和Flying的所有数据
grouped2.get_group(('Fire', 'Flying'))
4.组的迭代
for name,group in grouped2:
print(name)
print(group.shape)
二.数据透视表
1.数据透视表pivot_table
#示例数据
df_p = df.iloc[:10,0:6]
#做一些修改
df_p.loc[0:2,"姓名"] = "A"
df_p.loc[3:5,"姓名"] = "B"
df_p.loc[6:9,"姓名"] = "C"
df_p["类型2"] = df_p["类型2"].fillna("Flying")
df_p.rename(columns={"姓名":"组"},inplace=True)
df_p
#将组放在行上,类型1放在列上,计算字段为攻击力,如果没有指定,默认计算其均值
df_p.pivot_table(index="组",columns="类型1",values="攻击力")
#将组放在行上,类型1放在列上,计算攻击力的均值和计数
df_p.pivot_table(index="组",columns="类型1",values="攻击力",aggfunc=[np.mean,len])
#将组和类型1放在行上,类型2放在列上,计算攻击力的均值和计数
df_p.pivot_table(index=["组","类型1"],columns="类型2",values="攻击力",aggfunc=[np.mean,len])
#将组和类型1放在行上,类型2放在列上,计算生命值和攻击力的均值和计数
df_p.pivot_table(index=["组","类型1"],columns="类型2",values=["生命值","攻击力"],aggfunc=[np.mean,len])
#将组和类型1放在行上,类型2放在列上,计算生命值和攻击力的均值和计数,并且将缺失值填充为0
df_p1 = df_p.pivot_table(index=["组","类型1"],columns="类型2",values=["生命值","攻击力"],aggfunc=[np.mean,len],fill_value=0)
#将组和类型1放在行上,类型2放在列上,计算生命值和攻击力的均值和计数,将缺失值填充为0,并且增加总计行列
df_p.pivot_table(index=["组","类型1"],columns="类型2",values=["生命值","攻击力"],aggfunc=[np.mean,len],fill_value=0,margins=True)
2.重塑层次化索引
stack():将数据最内层的列旋转到行上
unstack():将数据最内层的行旋转到列上
#将数据最内层的列旋转到行上,也即是将类型2转移到行上
df_p1.stack()
#将数据最内层的行旋转到列上,也即是将类型1转移到列上
df_p1.unstack()
三.交叉表
crosstab
用于计算分组频率用的特殊透视表
#示例数据
df_p
#计算组和类型1的交叉频率
pd.crosstab(index=df_p["组"],columns=df_p["类型1"])
DataFrame——数据统计
阿雷边学边教python数据分析第3期——pandas与numpy
#示例数据
df = pd.read_csv("pokemon_data.csv",encoding="gbk")
一.简单随机抽样
#简单随机抽样,随机抽取5行数据
df.sample(n=5)
#设置抽样的权重,权重高的更有希望被选取
w = [0.2,0.3,0.5]
df.head(3).sample(n=2,weights=w)
抽样后是否放回,由replace参数控制
#抽样后不放回
df.head(5).sample(n=4,replace=False)
#抽样后放回
df.head(5).sample(n=4,replace=True)
二.描述性统计
#获得描述性统计信息
df.describe().round(1)
#均值
df["攻击力"].mean()
#标准差
df["攻击力"].std()
#求和
df["攻击力"].sum()
#中位数
df["攻击力"].median()
#最大值或最小值的索引idxmax,idxmin
df["攻击力"].idxmax()
#累计值
df["攻击力"].cumsum()
#频数分布
df["类型1"].value_counts()
三.协方差与相关性
#两变量的协方差
df["攻击力"].cov(df["防御力"])
#所有变量间的协方差
df.cov()
#两个变量间的相关系数
df["攻击力"].corr(df["防御力"])
#所有变量间的相关系数
df.corr()