期末复习-基于python的数据整理

发布时间 2023-12-19 08:31:42作者: E_sheep

一、pandas数据合并

pd.concat()

append()

pd.merge()

1.1 pd.concat()函数

pandas的pd.concat函数和numpy的np.concatenate函数类似

1)简单的合并
def make_df(indexs, columns):
    data = [[str(j)+str(i) for j in columns] for i in indexs]
    df = pd.DataFrame(data=data, index=indexs, columns= columns)
    return df

df1=make_df([1,2],['A','B'])
df2=make_df([3,4],['A','B'])
pd.concat([df1,df2])#默认是上下(垂直)合并
pd.concat([df1,df2], axis=1)#axis=1,左右合并(水平)合并
  • 忽略行索引ignore_index

    pd.concat([df1,df2], ignore_index=True)#ignore_index=True,忽略行索引,行索引就被重置从0开始
    
  • 使用多层索引keys

pd.concat([df1,df2], keys=['x','y'])#行索引变成多层
pd.concat([df1,df2], keys=['x','y'], axis=1)#也可以让列索引为多层,axis=1
2)不匹配合并

不匹配指的是合并的维度的索引不一致。例如纵向级联时列索引不一致,横向级联时行索引不一致

df3=make_df([1,2,3,4], ['A','B','C','D'])
df4=make_df([5,6,7,8], ['E','F','B','A'])
pd.concat([df3,df4])#对应索引没有值,默认用NaN填充
  • 外连接,默认使用的是外连接,没有对应索引使用NaN填充

    外连接类似并集,显示所有数据

pd.concat([df3,df4],join="outer")#和不写join参数是一样的效果
  • 内连接,只连接匹配的项
pd.concat([df3,df4],join="inner")#只显示交集的部分
1.2 append()函数
df3.append(df4)#将df4追加到df3
1.3 pd.merge()函数
  • 类似MySQL中表和表直接的合并
  • merge与concat的区别在于,merge需要依据某一共同的行或列来进行合并
  • 使用pd.merge()合并时,会自动根据两者相同column名称的那一列,作为key来进行合并
  • 每一列元素的顺序不要求一致.
1)一对一合并,只有一个共同列的,对应的值也只有一个的情况
df1 = pd.DataFrame({'name':['张三','李四','王五'],'id': [1, 2, 3],'age': [22,33,44]})
df2 = pd.DataFrame({'id': [2,3,4],'sex':['男','女','男'],'job': ['saler','CEO','Pro']})
pd.merge(df1,df2)#df1.merge(df2),默认是内连接,交集
2)多对一合并
df1 = pd.DataFrame({'name':['张三','李四','王五'],'id': [1, 2, 2],'age': [22,33,44]})
df2 = pd.DataFrame({'id': [2,3,4],'sex':['男','女','男'],'job': ['saler','CEO','Pro']})
pd.merge(df1,df2)#df1.merge(df2),会将df1的id为2分别和df2的id为2合并,得到2条数据
3)多对多合并
df1 = pd.DataFrame({'name':['张三','李四','王五'],'id': [1, 2, 2],'age': [22,33,44]})
df2 = pd.DataFrame({'id': [2,2,4],'sex':['男','女','男'],'job': ['saler','CEO','Pro']})
pd.merge(df1,df2)#df1.merge(df2),会将df1的id为2分别和df2的id为2合并,得到4条数据
4)key规范化
  • 使用on=显式指定哪一列为key,当2个DataFrame有多列相同时使用,如果不指定的话需要两列的数据都完全相同才会合并。

如果有多个相同列的情况,需要指定一列作为连接的字段

df1 = pd.DataFrame({'name':['张三','李四','王五'],'id': [1, 2, 3],'age': [22,33,44]})
df2 = pd.DataFrame({'id': [2,4,5],'name':['李四','Jack','Tom'],'job': ['saler','CEO','Pro']})
pd.merge(df1,df2,on='name')#df1.merge(df2,on='id')
  • 使用left_on和right_on指定左右两边的列作为key,当左右两边的key都不相等时使用
df1 = pd.DataFrame({'name':['张三','李四','王五'],'id': [1, 2, 3],'age': [22,33,44]})
df2 = pd.DataFrame({'id1': [2,4,5],'name1':['李四','Jack','Tom'],'job': ['saler','CEO','Pro']})
#直接调用df1.merge(df2)会报错,因为他们没有相同的列,这时需要使用left_on和right_on指定左右两边的列来连接
df1.merge(df2,left_on='id',right_on='id1')
  • 当左边的列和右边的index相同的时候,使用right index=True
df1 = pd.DataFrame({'name':['张三','李四','王五'],'id': [1, 2, 3],'age': [22,33,44]})
df2 = pd.DataFrame({'id1': [2,4,5],'name1':['李四','Jack','Tom'],'job': ['saler','CEO','Pro']})
#可以使用行索引作为连接的字段
df1.merge(df2,right_index=True,left_index=True)
#也可以一边用行索引,另一边用列名
df1.merge(df2,right_index=True,left_on='id')
5)内合并和外合并
  • 内合并:只保留两者都有的key(默认模式)how="inner"
df1 = pd.DataFrame({'name':['张三','李四','王五'],'id': [1, 2, 3],'age': [22,33,44]})
df2 = pd.DataFrame({'id': [2,4,5],'sex':['F','F','M'],'job': ['saler','CEO','Pro']})
df1.merge(df2)#默认是内合并(内连接)默认,类似数据库的inner join
df1.merge(df2, how="inner")#效果一样
  • 外合并:也叫外连接,how="outer",补充NaN
df1.merge(df2, how="outer")#外连接,会显示两个DataFrame的所有数据
  • 左合并,右合并:how="left",how="right"
df1.merge(df2, how="left")#左连接,显示左边df1的所有数据和右边df2的公共数据
df1.merge(df2, how="right")#右连接,显示df2的所有数据和左边df1的公共数据
6)列名冲突解决

当列冲突时,即有多个列名称相同的时候,需要时候on=来指定哪一个列作为key,配合suffixes指定冲突列名

可以使用suffixes=自己指定后缀

df1 = pd.DataFrame({'name':['张三','李四','王五'],'id': [1, 2, 3],'age': [22,33,44]})
df2 = pd.DataFrame({'id': [2,4,5],'name':['Jack','Tom','Lucy'],'job': ['saler','CEO','Pro']})
df1.merge(df2, on="id")#合并之后共同的列名name,分别变成了name_x,name_y
#也可以自己定义后缀
df1.merge(df2, on="id", suffixes=['_df1', "_df2"])
7)merge合并总结
  • 合并有三种现象:一对一,多对一,多对多;
  • 合并会默认找相同的列名进行合并,如果有多个列名相同,使用on来指定;
  • 如果没有列名相同,但是数据又相同,可以通过left_on,right_on分别指定要合并的列;
  • 如果想和index合并,使用left_index,right_index来指定;
  • 如果多个列相同,合并之后可以通过suffixes来区分;
  • 还可以通过how来控制合并的结果,默认是内合并,还有外合并outer,左合并left,右合并right.
1.4 练习1

1、根据以下数据,创建三个DataFrame,df1,df2,df3


raw_data_1 = {
        'subject_id': ['1', '2', '3', '4', '5'],
        'first_name': ['Alex', 'Amy', 'Allen', 'Alice', 'Ayoung'], 
        'last_name': ['Anderson', 'Ackerman', 'Ali', 'Aoni', 'Atiches']}

raw_data_2 = {
        'subject_id': ['4', '5', '6', '7', '8'],
        'first_name': ['Billy', 'Brian', 'Bran', 'Bryce', 'Betty'], 
        'last_name': ['Bonder', 'Black', 'Balwner', 'Brice', 'Btisan']}

raw_data_3 = {
        'subject_id': ['1', '2', '3', '4', '5', '7', '8', '9', '10', '11'],
        'test_id': [51, 15, 15, 61, 16, 14, 15, 1, 61, 16]}

2、 将df1和df2两个数据按照行的维度进行合并,命名为all_data

3、 将df1和df2两个数据按照列的维度进行合并,命名为all_data_col

4、按照subject_id的值对all_data和df3作合并

5、对df1和df2按照subject_id作内连接

5、对df1和df2按照subject_id作外连接

#1
df1 = pd.DataFrame(raw_data_1, columns = ['subject_id', 'first_name', 'last_name'])
df2 = pd.DataFrame(raw_data_2, columns = ['subject_id', 'first_name', 'last_name'])
df3 = pd.DataFrame(raw_data_3, columns = ['subject_id','test_id'])
#2
all_data=pd.concat([df1,df2])
#3
all_data_col=pd.concat([df1,df2], axis=1)
#4
pd.merge(all_data, df3, on='subject_id')
#5
pd.merge(df1, df2, on='subject_id', how='inner')
pd.merge(df1, df2, on='subject_id', how='outer')

二、pandas缺失值处理

#导包
import pandas as pd
import numpy as np

有两种丢失数据(空值):

  • None
  • np.nan
1.None
  • None是Python自带的,是Python中的空对象。None不能参与到任何计算中。
  • object类型的运算要比int类型的运算慢得多(一般不使用这种None)
#%timeit 计算当前行的代码运行时间。np.arrange创建数组,这里创建10的6次方个一维数组,然后求数组元素的和,计算这段代码的运行时间
%timeit np.arange(1e6, dtype=object).sum()#np.arrange
#把数据类型改成np.int32,再看看计算时间
%timeit np.arange(1e6, dtype=np.int32).sum()
2.np.nan
  • np.nan是浮点类型,能参与到计算中。但是计算的结果总是NaN
type(np.nan)#查看np.nan的数据类型
  • 但可以使用np.nan*()函数来计算nan,此时会过滤调nan

    n=np.array([1,2,3,np.nan,5,6])
    np.sum(n)#得到nan
    np.nansum(n)#会过滤调nan,得到17
    np.nanmean(n)#求平均值
    
3.pandas的None与NaN
1)Pandas的None和np.nan都视作np.nan
  • 创建DataFrame
data=np.random.randint(1,100,size=(5,5))
df = pd.DataFrame(data, columns=list("ABCDE"))
  • 使用DataFrame的行索引和列索引修改DataFrame数据
#行索引从0开始
df.loc[1,'B']=np.nan#loc先取行,再取列,取第1行,B列的值,赋值nan
df.loc[2,'C']=None#取第2行,C列的值,赋值None
#打印df,发现都变成了NaN
print(df)
#单独取出来打印也是nan
print(df.loc[1,'B'],df.loc[2,'C'])
2)Pandas的None与np.nan的操作
  • isnull()
  • notnull()
  • all()
  • any()
  • dropna():删除缺失数据
  • fillna():填充缺失数据

(1)判断函数

  • isnull()
  • notnull()
df.isnull()#为空的是True,非空为False
df.notnull()#为空的是False,非空为True
#all():必须全部为True,才是True,类似and
#any():只要一个为True,则为True,类似or
df.isnull().any()#常用的函数,这一列只要有为True的,就会返回True,找有空的列
#df.isnull().all()#少用,必须全部为空的行或列才为True
df.notnull().all()#常用,找没有空的列
#df.notnull().any()#少用
#如果要找空的行怎么办?需要用到axis参数,axis默认是0
df.isnull().any(axis=1)
#如果要找没有空的行怎么办?需要用到axis参数,axis默认是0
df.notnull().all(axis=1)
  • 使用bool值索引过滤数据
#过滤数据,可以对行过滤,也可以对列过滤
#行过滤
line_data=df.isnull().any(axis=1)#有空的行会返回True
#要取出非空的行可以对line_data进行取反,~line_data就是取反
print(~line_data)
df[~line_data]
#也可以使用notnull过滤空数据
line_data1=df.notnull().all(axis=1)#没有空的行会返回True
df[line_data1]#这时候就不需要取反

#列过滤
columns_data=df.isnull().any()#有空的列会返回True
#要取出非空的列可以对columns_data进行取反,~columns_data就是取反
df.loc[:,~columns_data]#需要用到loc,:,行不变,
#也可以使用notnull过滤空数据
columns_data1=df.notnull().all()#没有空的列会返回True
df.loc[:,columns_data1]#这时候就不需要取反

(2)过滤函数

  • dropna()

可以选择过滤行或者过滤列,默认是过滤行

df.dropna()#默认删除有空的行
#如果需要删除有空的列,设置axis=1
df.dropna(axis=1)

也可以选择过滤的方式,how="all"

df.dropna(how="any")#默认how=any,和df.dropna()效果一样
df.dropna(how="all")#必须所有数据都为nan才会删除
#针对列,一样是设置axis=1
df.dropna(how="all", axis=1)

inplace=True修改原数据,在很多函数中都有这个参数

df2=df.copy()#复制一个df给df2
df2.dropna(inplace=True)#inplace=True,这时候没有返回值,会直接修改df2,默认inplace=False,不会修改原数据。

(3)填充函数Series/DataFrame

  • fillna()
#fillna有一个value参数,可以用来填充空值nan
df.fillna(value=100)#用100填充空值
#还有一个参数limit,限制填充的次数
df.fillna(value=100,limit=1)#并不会将所有的空值填充,一列只会填充一个,从上往下,从左往右
df.fillna(value=100,limit=1,axis=1)#一行只会填充一个空值

可以选择向前填充还是向后填充

#method参数可以设置向前填充或者向后填充
#method参数的值可以设置 backfill, bfill, pad, ffill, None,默认是 None
#pad和ffill效果一样
#backfill和bfill效果一样
df.fillna(method='ffill')#向前填充
df.fillna(method='bfill')#向后填充
#也可以向左向右填充,需要加上我们的维度参数axis
df.fillna(method='ffill', axis=1)#向左填充
df.fillna(method='bfill', axis=1)#向右填充
3.练习2

1、将快餐店数据chipotle.tsv导入,命名df1

2、查看前10行数据

3、数据集中有多少个列?

4、打印出全部的列名称

5、查看数据行索引

6、查看列是否有空值

7、查看行是否有空值

8、取出非空的行,赋值给df2

9、删除有空值的行,赋值给df3

10、df3中的choice_description,下单次数最多的前20个商品是什么?

path1='D:\work\school\课件\大数据预处理\课外练习\exercise_data\chipotle.tsv'
#1
df1 = pd.read_csv(path1, sep = '\t')
#2
df1.head(10)#df1.loc[:9],df1.iloc[0:10]
#3
df1.shape[1]
#4
df1.columns
#5
df1.index
#6
df1.isnull().any()
#7
df1.isnull().any(axis=1)
#8
df2=df[~line_data]
#9
df3=df1.dropna()
#10
df['choice_description'].value_counts().head(20)

三、pandas重复值处理

1.删除重复行
#把之前创建DataFrame的函数拿过来
def make_df(indexs, columns):
    data = [[str(j)+str(i) for j in columns] for i in indexs]
    df = pd.DataFrame(data=data, index=indexs, columns= columns)
    return df
  • 使用duplicated()函数检测是否有重复的行
    • 返回元素为布尔类型的Series对象
    • 每个元素对应一行,如果该行不是第一次出现,则元素为True
#一般只考虑行重复,列重复很少会出现
df=make_df([1,2,3,4], list("ABCD"))
#让第一行和第二行重复
df.loc[1] = df.loc[2]
df.duplicated()#判断是否和前面的行重复
#有一个参数keep,有三个值,first,last,False,默认是first,保留第一行,last保留最后一行,False不保留任何一行
df.duplicated(keep="first")#和df.duplicated()效果一样,保留第一行
df.duplicated(keep="last")#保留最后一行
df.duplicated(keep=False)#不保留任何一行,标记所有的重复行
#以上是行和行之间完全重复的情况,有时候我们的数据行之间不一定是完全重复的,可能是某个字段重复
df.loc[1,'D']="DDD"#修改第一行的值,使它和第二行不完全重复再调用duplicated()函数
df.duplicated()#全部返回了False,没有完全重复的行
#有时候我们只需要判断某个字段是否重复,这里就有一个subset参数
#subset:子集的意思,判断某个列或者某几个列是否重复
df.duplicated(subset=['A'])#判断A这一列是否有重复值,或者subset=['A','B','D'],判断A,B,D三列是否有重复值
  • 使用drop_duplicates()函数删除重复的行
df.drop_duplicates()#行之间完全重复才会删除
df.drop_duplicates(subset=['A','B'])#A,B这两列完全重复删除
#它也有keep参数,和duplicated类似

四、数据映射

映射的含义:创建一个映射关系列表,把values元素和一个特定的标签或字符串绑定。

包含三种操作:

  • replace()函数:替换元素
  • map()函数,新建一列,最重要,用于Series
  • rename()函数,替换索引
(1)replace()函数:替换元素

使用replace()函数,对values进行替换操作

index=['张三','李白','杜甫','李四']
columns=['Python','预处理','数据挖掘','NoSQL']
data=np.random.randint(1,100,size=(4,4))
df=pd.DataFrame(data=data,index=index,columns=columns)
df.replace({5:50})#使用replace替换元素,5变成50
df.replace({5:50,1:100})#替换多个
(2)map()函数:适合处理某一单独的列

map()函数中可以使用lambda函数

#拷贝一下df
df2=df.copy()
#不能直接使用df2.map(),因为不支持DataFrame
#map()一般用于Series数据结构
#将Python成绩都加上10
df2['Python'].map(lambda x: x+10)
#也可以新增一列
df2['pandas']=df2['Python'].map(lambda x: x+5)
#新增一列,判断NoSQL的成绩是否及格
df2['NoSQL是否及格过']=df2['NoSQL'].map(lambda x: '及格' if x >= 60 else '不及格')

map()函数也可以使用普通函数

#新增一列,判断预处理成绩,<60为E,60-70为D,70-80为C,80-90为B,90-100为A
def calScoreLevel(x):
    if x < 60:
        return 'E'
    elif x >= 60 and x < 70:
        return 'D'
    elif x >= 70 and x < 80:
        return 'C'
    elif x >= 80 and x < 90:
        return 'B'
    else:
        return 'A'
df2['预处理成绩等级']=df2['预处理'].map(calScoreLevel)
(3)rename()函数,替换索引
df3=df.copy()
df3.rename({"张三":"Jack"})
#如果修改列呢?不能直接使用df3.rename({"NoSQL":"分布式数据库"}),需要加上axis
df3.rename({"NoSQL":"分布式数据库"}, axis=1)
#也可以使用index,columns参数
df3.rename(index={"张三":"Jack"})
df3.rename(columns={"NoSQL":"分布式数据库"})

还可以重置索引,使用reset_index()函数

df3.reset_index()#会将索引重置为0,1,2,3,原来的索引就变成了一个新的列

还可以将某一列数据作为行索引,使用set_index()函数设置行索引

df3.set_index(keys=['Python'])#使用Python这一列的数据作为行索引,原来的索引就没有了
(4)apply()函数,既支持Series,也支持DataFrame

apply可以使用lamda函数

#用于Series,其中x表示的是Series中的元素
df['Python'].apply(lambda x: True if x > 60 else False)
#用于DataFrame,x是DataFrame中某一列或者某一行的Series数据
df.apply(lambda x: x.mean())#默认求的是每一列的平均值
#如果要求每一行的,则需要使用axis参数
df.apply(lambda x: x.mean(), axis=1)

apply也可以使用普通函数

def fn(x):
    return x.sum()
df.apply(fn)
df.apply(fn, axis=1)

普通函数也可以返回多个值

def fn2(x):
	return (x.mean(), x.sum())
df.apply(fn2)

applymap()函数是DataFrame专有的

#x是每个元素
df.applymap(lambda x: x+10)
(5)transform()函数

既可以处理Series,也可以处理DataFrame

#Series中使用transform
#可以执行多项计算
df['Python'].transform([np.sqrt,np.exp])

#DataFrame中使用transform
def convert(x):
    if x.mean() > 50:
        return x * 5
    else:
        return x * -10
df.transform(convert)#默认处理每一列
df.transform(convert, axis=1)#对行处理

五、pandas异常值处理

1、常用函数介绍
  • describe():查看每一列的描述性量
df.describe()#可以得到每一列的个数,平均值,最大值,最小数,标准差,25%分位数,中位数,75%分位数
#也可以查看其他分位数
df.describe([0.1,0.3,0.4,0.6,0.99])#0.1和0.99在工作中会经常用
#如果列数比较多,比如几十列,就可以转换一下
df.describe([0.1,0.3,0.4,0.6,0.99]).T
#使用describe()主要查看最大最小值,看值的范围是否超出,是否存在异常值
  • df.std():可以求DataFrame每一列的标准差
df.std()#得到每一列的标准差,其实在describe中已经有
  • df.drop():删除特定索引
df2=df.copy()
df2.drop('张三')#删除行索引
#如果想删除列索引,需要使用axis参数
df2.drop("Python", axis=1)
#如果要删除多列或者多行呢?
df2.drop(['张三','李四'])

#还可以使用index,columns删除行和列
df2.drop(index='张三')#删除行
df2.drop(columns='Python')#删除列
#还可以加inplace=True,修改原数据
  • unique():唯一,去重

这里需要注意,unique()函数不是DataFrame的函数,所以不能使用df.unique()去重,它是Series的函数,所以我们只能对某一列或者某一行进行去重。

df['Python'].unique()#直接使用
  • df.query():按条件查询
#比如查询NoSQL中成绩为80的所有行
df.query("NoSQL==80")#也可以使用大于号小于号,比如df.query("NoSQL > 60")
#还可以使用and,or,&,|,in
df.query("NoSQL > 80 and 预处理 > 80")
df.query("NoSQL > 80 & 预处理 > 80")
df.query("NoSQL > 80 or 预处理 > 80")
df.query("NoSQL > 80 | 预处理 > 80")
df.query("NoSQL in [5,70,78]")

#还可以使用变量
n = 80
df.query("NoSQL == @n")#使用变量的时候不能直接写,需要使用@符合,这里就相当于NoSQL==80,变量n的值是80
l = [5,70,78]
df.query("NoSQL in @l")

通过query可以过滤掉异常值,比如NoSQL分数大于100和小于0的就不要了,df.query("NoSQL >= 0 and NoSQL < =100")

  • df.sort_values():根据值排序,常用
  • df.sort_index():根据索引排序
df.sort_values("预处理")#需要指定按某列或某行排序,默认是升序
df.sort_values("预处理", ascending=False)#ascending=False,降序,从大到小
#也可以使用axis=1,按行索引名排序(不常用)
df.sort_values('张三', axis=1)
#按索引名排序,不常用,了解
df.sort_index()
df.sort_index(axis=1)
  • df.info():查看数据信息(常用)
2、练习3

1、新建一个形状为10000*3的标准正态分布的DataFrame(np.random,randn),去除掉所有满足以下情况的行:其中任一元素绝对值大于3倍标准差的行。

用到绝对值df.abs(),标准差df.std()

第一步:找到绝对值大于三倍标准差的元素

第二步:使用any找到大于三倍标准差的行

第三步:使用bool值索引,过滤异常值

  • 注意:每次运行结果都不一样,因为使用的是随机数创建DataFrame的Data

2、读取文件,并完成以下数据处理。

(1)读取文件 ’医疗数据.csv‘,命名df1;

(2)删除df1中存在缺失值的行,需要设置inplace

(3)统计完全重复数据的行数

(4)删除df1中的完全重复数据

(5)将所有的时间数据(字段中带有RQ的)转换为年月日,转换年月日的方法如下:

def trans_time(time_stamp):
    timeStamp = time_stamp
    timeArray = time.localtime(timeStamp)
    Time = time.strftime("%Y-%m-%d", timeArray)
    return Time
df = pd.DataFrame(data=np.random.randn(10000,3))
#求标准差
df.std()
#绝对值abs
cond=df.abs() > 3 * df.std()#找到每个元素是否大于三倍标准差
#找到大于三倍标准差的行
cond2=cond.any(axis=1)
#bool值索引,过滤异常值(大于3倍标准差)
df.loc[~cond2]
df1=pd.read_csv("D:\work\school\课件\大数据预处理\教材案例\第8章\医疗数据.csv", encoding='GBK')
df1.dropna(axis=0, inplace=True)
df1.duplicated().sum()
df1.drop_duplicates(inplace=True,keep='first')
def trans_time(time_stamp):
    timeStamp = time_stamp
    timeArray = time.localtime(timeStamp)
    Time = time.strftime("%Y-%m-%d", timeArray)
    return Time
df1['RYRQ'] = df1['RYRQ'].map(lambda x:trans_time(x))
df1['CYRQ'] = df1['CYRQ'].map(lambda x:trans_time(x))
df1['JSRQ'] = df1['JSRQ'].map(lambda x:trans_time(x))

六、pandas数学函数

聚合函数:
count(): 非空值的数量
max():最大值
min():最小值
median():中位数
sum():求和
mean():每一行的平均值
std():标准差
var():方差

其他函数:
value_counts(): 统计元素出现次数
cumsum():累加
cumprod():累乘

七、pandas分组

数据聚合是数据处理的最后一步,通常是要使每一个数组生成一个单一的数值。

数据分类处理:

  • 分组:先把数据分为几组
  • 用函数处理:为不同组的数据应用不同的函数以转换数据
  • 合并:把不同组得到的结果合并起来

数据分类处理的核心: groupby()函数

df=pd.DataFrame(
  {
      'color':['red','green','red','yellow','blue','blue','red'],
      'price':[3,4,5,1,2,2,3]
  }
)
#使用groupby的时候,需要时by参数指定按某列或某几列分组,一般都是按列分组,很少按行分组
df.groupby(by='color')

.groups属性查看各行的分组情况:

#不能直接使用df.groups查看,而是使用groupby之后使用
df.groupby(by='color').groups

一般分组会和一些聚合函数进行使用

#比如,分组后求和
df.groupby(by='color').sum()
练习4

假设菜市场张大妈在卖菜,有以下属性:

菜品(item):萝卜,白菜,辣椒,冬瓜

颜色(color): 白,青,红

重量(weight)

价格(price)

​ 1、要求以属性作为列索引,新建一个ddd

​ 2、对ddd进行聚合操作,求出颜色为白色的价格总和

​ 3、对ddd进行聚合操作,分别求出萝卜的所有重量以及平均价格

​ 4、使用merge合并菜品的总重量及平均价格

ddd = pd.DataFrame(
data={
	'item':['萝卜','白菜','辣椒','冬瓜','萝卜','白菜','辣椒','冬瓜'],
	'color':['白','青','红','白','青','红','白','青'],
	'weight':[10,20,10,10,30,40,50,60],
	'price':[0.99,1.99,2.99,3.99,4,5,6,7]
	}
)
#2、对ddd进行分组聚合操作,求出颜色为白色的价格总和
s1=ddd.groupby(by='color')['price'].sum()#得到的是Series
#通过显示索引访问
s1.loc['白']
#通过隐式索引访问
s1.iloc[0]
#价格price用两个[[]]括起来,得到的就是DataFrame
d1=ddd.groupby(by='color')[['price']].sum()#得到的是DataFrame
#通过行索引访问获取白色的价格总和
d1.loc['白']
d1.iloc[0]
#3、对ddd进行聚合操作,分别求出萝卜的所有重量以及平均价格	
s1=ddd.groupby(by='item')['weight'].sum()#得到的是Series
s1.loc['萝卜']
s2=ddd.groupby(by='item')['price'].mean()#得到的是Series
s2.loc['萝卜']
#4、使用merge合并总重量及平均价格
d1=ddd.groupby(by='item')[['weight']].sum()#得到的DataFrame
d2=ddd.groupby(by='item')[['price']].mean()#得到的DataFrame
d1.merge(d2, left_index=True, right_index=True)

八、pandas分箱操作

  • 分箱操作就是将连续型数据离散化
  • 分箱操作分为等距分箱和等频分箱

商品价格,有很多,有1,2,3,4,5,60,70,80,200,300,称这种数据为连续型数据,现在想统计,1-10的价格,10-100的价格,100-1000的价格,就使用到分箱

data = np.random.randint(1,100,size=(5,3))
df = pd.DataFrame(data=data, columns=['Python', '预处理', 'NoSQL'])
df
1、等宽分箱(等距分箱)

pd.cut()常用,重点掌握

#使用pd.cut()函数,这个函数有两个参数必须要传,x参数,需要分箱的数据,bins参数,需要分几个箱
s=pd.cut(x=df.Python, bins=4)#对Python列进行分箱操作
print(s)#打印查看分箱情况
s.value_counts()#统计每个箱的个数
#还可以指定bins的区间范围,也叫分箱的断点
s=pd.cut(x=df.Python, bins=[0,60,70,80,90,100])#对Python成绩分为0-60,60-70,70-80,80-90,90-100区间内
print(s)#打印查看分箱情况
s.value_counts()#统计每个箱的个数
#还可以指定right参数,右边的范围是否包含,默认是左开右闭,right=True,左闭右开
#还可以指定箱的名称,使用labels参数设置箱的名称,比如成绩分为E,D,B,C,A五个等级
s=pd.cut(
    df.Python, #需要分箱的数据
    bins=[0,60,70,80,90,100],#分箱的断点
    right=True,       #左闭右开,默认是左开右闭
    labels=['E','D','C','B','A']#分箱后分类的标签
)
2、等频分箱

pd.qcut()用的不多

s=pd.cut(
    df.Python, #需要分箱的数据
    q=5,#表示5等分
    labels=['E','D','C','B','A']#分箱后分类的标签
)

九、pandas抽样

  • 使用.take()函数排列
  • 可以借助np.random.permutation()函数随机排列

无放回抽样:不会出现重复值

比如抽奖,抽到一等奖之后,这个一等奖不会再放回去,就是无放回抽样

#可以使用take()函数对行或者列进行排列
df2.take([2,3,0,1])#使用行索引,对行进行排列,这里的索引不能超过行索引的最大值
#也可以使用axis=1对列进行排列
df2.take([2,1,3,0], axis=1)#对列排列

#如果想要随机排列,就可以使用numpy的方法np.random.permutation()
#随机排列
np.random.permutation([0,1,2,3])#每次运行都会随机得到一个一维数组,并且值为我们传入的0,1,2,3,不会重复。

#模拟无放回抽样,可以认为依次取出随机行,没有重复值
df2.take(np.random.permutation([0,1,2,3]))

有放回抽样:可能会出现重复值

#有放回抽样,使用np.random.randint()
np.random.randint(0,4,size=5)#随机产生生成一维数组,数组里面的值是可能有重复的
#结合take()函数
df2.take(np.random.randint(0,4,size=10))#随机范围只能是0-4,因为df2的行索引范围是0,1,2,3,size可以任意设置,取的越多,重复的值就越多,这里是取10行,可以认为是有放回抽样,取出来又放回去,就有可能取到重复值。