数据分析04-pandas(apply函数、排序、数据合、分组聚合、透视表、交叉表及项目分析)

apply函数

pandas提供了apply函数方便的处理Series与DataFrame;apply函数支持逐一处理数据集中的每个元素都会执行一次目标函数,把返回值存入结果集中。:

# series.apply()
ary = np.array(['80公斤','83公斤','78公斤','74公斤','84公斤'])
s = pd.Series(ary)
def func(x):
    return x[:2]
s.apply(func)

# dataframe.apply()
def func(x):
    x[pd.isna(x)] = x.mean()
    return x
ratings.apply(func, axis=1)

排序

Pandas有两种排序方式,它们分别是按标签与按实际值排序。

import numpy as np

d = {'Name':pd.Series(['Tom','James','Ricky','Vin','Steve','Minsu','Jack','Lee','David','Gasper','Betina','Andres']),
 'Age':pd.Series([25,26,25,23,30,29,23,34,40,30,51,46]),
 'Rating':pd.Series([4.23,3.24,3.98,2.56,3.20,4.6,3.8,3.78,2.98,4.80,4.10,3.65])}
unsorted_df = pd.DataFrame(d)
按标签(行)排序

使用sort_index()方法,通过传递axis参数和排序顺序,可以对DataFrame进行排序。 默认情况下,按照升序对行标签进行排序。

# 按照行标进行排序
sorted_df=unsorted_df.sort_index()
print (sorted_df)
# 控制排序顺序
sorted_df = unsorted_df.sort_index(ascending=False)
print (sorted_df)
按标签(列)排序
# 按照列标签进行排序
sorted_df=unsorted_df.sort_index(axis=1)
print (sorted_df)
按某列值排序

像索引排序一样,sort_values()是按值排序的方法。它接受一个by参数,它将使用要与其排序值的DataFrame的列名称。

sorted_df = unsorted_df.sort_values(by='Age')
print (sorted_df)
# 先按Age进行升序排序,然后按Rating降序排序
sorted_df = unsorted_df.sort_values(by=['Age', 'Rating'], ascending=[True, False])
print (sorted_df)

数据合并

concat

concat函数是在pandas的方法,可以根据不同的轴合并数据集。

r = pd.concat(datas, axis=0, join='outer', ignore_index=False, 
              keys=['x', 'y', 'z'])

纵向合并:

在这里插入图片描述

横向合并:

在这里插入图片描述

merge & join

panda具有全功能、高性能的内存连接操作,与SQL之类的关系数据库非常相似。与其他开源实现相比,这些方法的性能要好得多(在某些情况下要好一个数量级以上)

pandas提供了merge函数实现高效的内存链接操作:

pd.merge(left, right, how='inner', on=None, left_on=None, right_on=None,left_index=False, right_index=False)
参数名称说明
left接收DataFrame或Series。表示要添加的新数据。无默认。
right接收DataFrame或Series。表示要添加的新数据。无默认。。
how接收inner,outer,left,right。表示数据的连接方式。默认为inner。
on接收string或sequence。表示外键字段名。默认为None。
left_on接收string或sequence。关联操作时左表中的关联字段名。
right_on接收string或sequence。关联操作时右表中的关联字段名。
left_index接收boolean。表示是否将left参数接收数据的index作为连接主键。默认为False。
right_index接收boolean。表示是否将right参数接收数据的index作为连接主键。默认为False。
sort接收boolean。表示是否根据连接键对合并后的数据进行排序。默认为False。
suffixes接收接收tuple。表示用于追加到left和right参数接收数据重叠列名的尾缀默认为(’_x’, ‘_y’)。

合并两个DataFrame:

import pandas as pd
left = pd.DataFrame({
         'student_id':[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20],
         'student_name': ['Alex', 'Amy', 'Allen', 'Alice', 'Ayoung', 'Billy', 'Brian', 'Bran', 'Bryce', 'Betty', 'Emma', 'Marry', 'Allen', 'Jean', 'Rose', 'David', 'Tom', 'Jack', 'Daniel', 'Andrew'],
         'class_id':[1,1,1,2,2,2,3,3,3,4,1,1,1,2,2,2,3,3,3,2], 
         'gender':['M', 'M', 'F', 'F', 'M', 'M', 'F', 'F', 'M', 'M', 'F', 'F', 'M', 'M', 'F', 'F', 'M', 'M', 'F', 'F'], 
         'age':[20,21,22,20,21,22,23,20,21,22,20,21,22,23,20,21,22,20,21,22], 
         'score':[98,74,67,38,65,29,32,34,85,64,52,38,26,89,68,46,32,78,79,87]})
right = pd.DataFrame(
         {'class_id':[1,2,3,5],
         'class_name': ['ClassA', 'ClassB', 'ClassC', 'ClassE']})
# 合并两个DataFrame
data = pd.merge(left,right)
print(data)

其他合并方法同数据库相同:

合并方法SQL等效描述
leftLEFT OUTER JOIN使用左侧对象的键
rightRIGHT OUTER JOIN使用右侧对象的键
outerFULL OUTER JOIN使用键的联合
innerINNER JOIN使用键的交集

实验:

# 合并两个DataFrame (左连接)
rs = pd.merge(left,right,on='subject_id', how='right')
print(rs)
# 合并两个DataFrame (左连接)
rs = pd.merge(left,right,on='subject_id', how='outer')
print(rs)
# 合并两个DataFrame (左连接)
rs = pd.merge(left,right,on='subject_id', how='inner')
print(rs)

分组聚合

pandas提供了功能类似于数据库中group by语句的用于拆分数据组的方法pd.groupby();该方法提供的是分组聚合步骤中的拆分功能,能根据索引或字段对数据进行分组(Split) 进而针对得到的多组数据执行聚合操作(Apply),最终合并为最终结果(Combine)。
在这里插入图片描述

分组

groupby方法的参数及其说明:

DataFrame.groupby(by=None, axis=0, as_index=True, sort=True)
参数名称说明
by接收list,string,mapping或generator。用于确定进行分组的依据。无默认。
axis接收int。表示操作的轴向,默认对行进行操作。默认为0。
as_index接收boolearn。表示聚合后的聚合标签是否以DataFrame索引形式输出。默认为True。
sort接收boolearn。表示是否对分组依据分组标签进行排序。默认为True。

用groupby方法分组后的结果并不能直接查看,而是被存在内存中,输出的是内存地址。实际上分组后的数据对象(Groupby对象)类似Series与DataFrame,是pandas提供的一种对象。

Groupby对象的常用方法:

方法说明
groupObject.get_group(‘A’)返回A组的详细数据
groupObject.size()返回每一组的频数
grouped = data.groupby(by=['class_id', 'gender'])
grouped.get_group((1, 'M'))
grouped = data.groupby(by=['class_id', 'gender'])
grouped.get_group((1, 'M'))
聚合

聚合函数为每个组返回聚合值。当创建了分组(groupby)对象,就可以对每个分组的其他字段数据执行求和、求标准差等操作。

使用聚合函数agg进行组内计算:

grouped = data.groupby(by='class_id')
grouped.agg({'score':np.mean})

对于某个字段希望只做求均值操作,而对另一个字段则希望只做求和操作,可以使用字典的方式,将两个字段名分别作为key:

grouped.agg({'age':np.max, 'score':np.mean})

还可以这样:

result = grouped.agg(
    {'age':np.max, 'score':[np.mean, np.max]})

pandas支持的聚合函数有:

方法名称说明
count计算分组的数目,包括缺失值。
head返回每组的前n个值。
max返回每组最大值。
mean返回每组的均值。
median返回每组的中位数。
cumcount对每个分组中组员的进行标记,0至n-1。
size返回每组的大小。
min返回每组最小值。
std返回每组的标准差。
sum返回每组的和。

透视表与交叉表

透视表

透视表(pivot table)是各种电子表格程序和其他数据分析软件中一种常见的数据汇总工具。它根据一个或多个键对数据进行分组聚合,并根据每个分组进行数据汇总

# 以class_id与gender做分组汇总数据,默认聚合统计所有列
print(data.pivot_table(index=['class_id', 'gender']))

# 以class_id与gender做分组汇总数据,聚合统计score列
print(data.pivot_table(index=['class_id', 'gender'], values=['score']))

# 以class_id与gender做分组汇总数据,聚合统计score列,针对age的每个值列级分组统计
print(data.pivot_table(index=['class_id', 'gender'], values=['score'], columns=['age']))

# 以class_id与gender做分组汇总数据,聚合统计score列,针对age的每个值列级分组统计,添加行、列小计
print(data.pivot_table(index=['class_id', 'gender'], values=['score'], columns=['age'], margins=True))

# 以class_id与gender做分组汇总数据,聚合统计score列,针对age的每个值列级分组统计,添加行、列小计
print(data.pivot_table(index=['class_id', 'gender'], values=['score'],  columns=['age'], margins=True, aggfunc='max'))
交叉表

交叉表(cross-tabulation, 简称crosstab)是一种用于计算分组频率的特殊透视表

# 按照class_id分组,针对不同的gender,统计数量
print(pd.crosstab(data.class_id, data.gender, margins=True))

项目:分析影响学生成绩的因素

资源文件下载

https://download.csdn.net/download/yegeli/12562286
在我的资源中下载:StudentsPerformance.csv

字段说明
gender性别
race/ethnicity种族
parental level of education父母教育水平
lunch午餐
test preparation course是否通过预科考试
math score数学得分
reading score阅读得分
writing score写作得分
学生成绩影响因素分析
import numpy as np
import pandas as pd
data = pd.read_csv('StudentsPerformance.csv')
data['total score'] = data.sum(axis=1)
# 参数number,object意为:统计数字列与字符串列
data.describe(include=['number', 'object'])
genderrace/ethnicityparental level of educationlunchtest preparation coursemath scorereading scorewriting scoretotal score
count100010001000100010001000.000001000.0000001000.0000001000.000000
unique25622NaNNaNNaNNaN
topfemalegroup Csome collegestandardnoneNaNNaNNaNNaN
freq518319226645642NaNNaNNaNNaN
meanNaNNaNNaNNaNNaN66.0890069.16900068.054000203.312000
stdNaNNaNNaNNaNNaN15.1630814.60019215.19565742.771978
minNaNNaNNaNNaNNaN0.0000017.00000010.00000027.000000
25%NaNNaNNaNNaNNaN57.0000059.00000057.750000175.000000
50%NaNNaNNaNNaNNaN66.0000070.00000069.000000205.000000
75%NaNNaNNaNNaNNaN77.0000079.00000079.000000233.000000
maxNaNNaNNaNNaNNaN100.00000100.000000100.000000300.000000
# 分析性别对学习成绩的影响(按性别分组)
data.pivot_table(index='gender')
math scorereading scoretotal scorewriting score
gender
female63.63320572.608108208.70849472.467181
male68.72821665.473029197.51244863.311203

总体来说,女生的成绩普遍比较好,但是男生更善于数学。

# 分析种族对学习成绩的影响
data.pivot_table(index='race/ethnicity')
math scorereading scoretotal scorewriting score
race/ethnicity
group A61.62921364.674157188.97752862.674157
group B63.45263267.352632196.40526365.600000
group C64.46395069.103448201.39498467.827586
group D67.36259570.030534207.53816870.145038
group E73.82142973.028571218.25714371.407143

种族划分(优秀-及格): E - D - C - B - A

# 分析父母教育水平对学习成绩的影响
r = data.pivot_table(index='parental level of education')
r.sort_values(by='total score', ascending=False)
math scorereading scoretotal scorewriting score
parental level of education
master's degree69.74576375.372881220.79661075.677966
bachelor's degree69.38983173.000000215.77118673.381356
associate's degree67.88288370.927928208.70720769.896396
some college67.12831969.460177205.42920468.840708
some high school63.49720766.938547195.32402264.888268
high school62.13775564.704082189.29081662.448980

父母受教育水平越高,学习成绩越好。

# 分析中午饭学习成绩的影响
r = data.pivot_table(index='lunch')
r.sort_values(by='total score', ascending=False)
math scorereading scoretotal scorewriting score
lunch
standard70.03410971.654264212.51162870.823256
free/reduced58.92112764.653521186.59718363.022535
# 分析中午饭学习成绩的影响
r = data.pivot_table(index='test preparation course')
r.sort_values(by='total score', ascending=False)
math scorereading scoretotal scorewriting score
test preparation course
completed69.69553173.893855218.00838074.418994
none64.07788266.534268195.11682264.504673
r = data.pivot_table(index=['gender','test preparation course'])
r
math scorereading scoretotal scorewriting score
gendertest preparation course
femalecompleted67.19565277.375000223.36413078.793478
none61.67065969.982036200.63473168.982036
malecompleted72.33908070.212644212.34482869.793103
none66.68831262.795455189.13311759.649351
分析前100名与后100名同学的不同情况
r = data.sort_values(by='total score', ascending=False)
top100 = r.head(100)
tail100 = r.tail(100)
r1 = pd.DataFrame({'top100':top100['gender'].value_counts(),
              'tail100':tail100['gender'].value_counts()})
r1
tail100top100
female3866
male6234
data['parental level of education'].value_counts()
some college          226
associate's degree    222
high school           196
some high school      179
bachelor's degree     118
master's degree        59
Name: parental level of education, dtype: int64
r2 = pd.DataFrame({'top100':top100['parental level of education'].value_counts(),
              'tail100':tail100['parental level of education'].value_counts()})
r2
tail100top100
associate's degree1729
bachelor's degree820
high school326
master's degree115
some college1421
some high school289

代码总结

import numpy as np
import pandas as pd
# apply() 应用于Series
ary = np.array(['80公斤','83公斤','78公斤','74公斤','84公斤'])
s = pd.Series(ary)
s
def func(item):
    return float(item[:-2])

s = s.apply(func)
s

0    80.0
1    83.0
2    78.0
3    74.0
4    84.0
dtype: float64
# apply() 应用于 DataFrame
ratings = pd.read_json('../../data/ratings.json')

def func(item):
    item[item.isna()] = item.mean()
    return item

ratings.apply(func, axis=0)
<ipython-input-7-ebdfbe0e051f>:5: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
  item[item.isna()] = item.mean()
John CarsonMichelle PetersonWilliam ReynoldsJillian HobartMelissa JonesAlex RobertsMichael Henry
Inception2.53.02.503.533.03.166667
Pulp Fiction3.53.53.003.544.04.500000
Anger Management3.01.53.253.023.73.166667
Fracture3.55.03.504.035.04.000000
Serendipity2.53.53.252.523.51.000000
Jerry Maguire3.03.04.004.533.03.166667
排序
d = {'Name':pd.Series(['Tom','James','Ricky','Vin','Steve','Minsu','Jack','Lee','David','Gasper','Betina','Andres']),
 'Age':pd.Series([25,26,25,23,30,29,23,34,40,30,51,46]),
 'Rating':pd.Series([4.23,3.24,3.98,2.56,3.20,4.6,3.8,3.78,2.98,4.80,4.10,3.65])}
unsorted_df = pd.DataFrame(d)
unsorted_df
NameAgeRating
0Tom254.23
1James263.24
2Ricky253.98
3Vin232.56
4Steve303.20
5Minsu294.60
6Jack233.80
7Lee343.78
8David402.98
9Gasper304.80
10Betina514.10
11Andres463.65
unsorted_df.sort_index(axis=1, ascending=True)  
AgeNameRating
025Tom4.23
126James3.24
225Ricky3.98
323Vin2.56
430Steve3.20
529Minsu4.60
623Jack3.80
734Lee3.78
840David2.98
930Gasper4.80
1051Betina4.10
1146Andres3.65
unsorted_df.sort_index(ascending=False)  
NameAgeRating
11Andres463.65
10Betina514.10
9Gasper304.80
8David402.98
7Lee343.78
6Jack233.80
5Minsu294.60
4Steve303.20
3Vin232.56
2Ricky253.98
1James263.24
0Tom254.23
按照某列字段进行排序
unsorted_df.sort_values(
    by=['Age', 'Rating'], ascending=[True, False])
NameAgeRating
6Jack233.80
3Vin232.56
0Tom254.23
2Ricky253.98
1James263.24
5Minsu294.60
9Gasper304.80
4Steve303.20
7Lee343.78
8David402.98
11Andres463.65
10Betina514.10


Merge & join
left = pd.DataFrame({
         'student_id':[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20],
         'student_name': ['Alex', 'Amy', 'Allen', 'Alice', 'Ayoung', 'Billy', 'Brian', 'Bran', 'Bryce', 'Betty', 'Emma', 'Marry', 'Allen', 'Jean', 'Rose', 'David', 'Tom', 'Jack', 'Daniel', 'Andrew'],
         'class_id':[1,1,1,2,2,2,3,3,3,4,1,1,1,2,2,2,3,3,3,2], 
         'gender':['M', 'M', 'F', 'F', 'M', 'M', 'F', 'F', 'M', 'M', 'F', 'F', 'M', 'M', 'F', 'F', 'M', 'M', 'F', 'F'], 
         'age':[20,21,22,20,21,22,23,20,21,22,20,21,22,23,20,21,22,20,21,22], 
         'score':[98,74,67,38,65,29,32,34,85,64,52,38,26,89,68,46,32,78,79,87]})
right = pd.DataFrame(
         {'class_id':[1,2,3,5],
         'class_name': ['ClassA', 'ClassB', 'ClassC', 'ClassE']})
left
student_idstudent_nameclass_idgenderagescore
01Alex1M2098
12Amy1M2174
23Allen1F2267
34Alice2F2038
45Ayoung2M2165
56Billy2M2229
67Brian3F2332
78Bran3F2034
89Bryce3M2185
910Betty4M2264
1011Emma1F2052
1112Marry1F2138
1213Allen1M2226
1314Jean2M2389
1415Rose2F2068
1516David2F2146
1617Tom3M2232
1718Jack3M2078
1819Daniel3F2179
1920Andrew2F2287
right
class_idclass_name
01ClassA
12ClassB
23ClassC
35ClassE
r = pd.merge(left, right, how='inner')
r
student_idstudent_nameclass_idgenderagescoreclass_name
01Alex1M2098ClassA
12Amy1M2174ClassA
23Allen1F2267ClassA
311Emma1F2052ClassA
412Marry1F2138ClassA
513Allen1M2226ClassA
64Alice2F2038ClassB
75Ayoung2M2165ClassB
86Billy2M2229ClassB
914Jean2M2389ClassB
1015Rose2F2068ClassB
1116David2F2146ClassB
1220Andrew2F2287ClassB
137Brian3F2332ClassC
148Bran3F2034ClassC
159Bryce3M2185ClassC
1617Tom3M2232ClassC
1718Jack3M2078ClassC
1819Daniel3F2179ClassC
分组聚合
grouped = r.groupby(by=['class_id', 'gender'])
# 返回每个分组的频数
grouped.size()

class_id  gender
1         F         3
          M         3
2         F         4
          M         3
3         F         3
          M         3
dtype: int64
# 获取某一个分组细节
grouped.get_group((2, 'F'))
student_idstudent_nameclass_idgenderagescoreclass_name
64Alice2F2038ClassB
1015Rose2F2068ClassB
1116David2F2146ClassB
1220Andrew2F2287ClassB
# 针对每小组执行聚合操作  agg()
grouped.agg({'score':np.mean})
r = grouped.agg({'score':np.mean, 'age':[np.max, np.min]})
r
scoreage
meanamaxamin
class_idgender
1F52.3333332220
M66.0000002220
2F59.7500002220
M61.0000002321
3F48.3333332320
M65.0000002220

透视表
data = pd.merge(left, right)
# 透视表
data.pivot_table(index='class_id')
agescorestudent_id
class_id
121.00000059.1666677.000000
221.28571460.28571411.428571
321.16666756.66666713.000000
data
student_idstudent_nameclass_idgenderagescoreclass_name
01Alex1M2098ClassA
12Amy1M2174ClassA
23Allen1F2267ClassA
311Emma1F2052ClassA
412Marry1F2138ClassA
513Allen1M2226ClassA
64Alice2F2038ClassB
75Ayoung2M2165ClassB
86Billy2M2229ClassB
914Jean2M2389ClassB
1015Rose2F2068ClassB
1116David2F2146ClassB
1220Andrew2F2287ClassB
137Brian3F2332ClassC
148Bran3F2034ClassC
159Bryce3M2185ClassC
1617Tom3M2232ClassC
1718Jack3M2078ClassC
1819Daniel3F2179ClassC
# 结果集中只希望看到score列的均值
data.pivot_table(index='class_id', values='score')
score
class_id
159.166667
260.285714
356.666667
# 依据class_id 与 gender 同时做分组
data.pivot_table(index=['class_id','gender'], values='score')
score
class_idgender
1F52.333333
M66.000000
2F59.750000
M61.000000
3F48.333333
M65.000000
data.pivot_table(index=['class_id','gender'], 
    columns='age', values='score')
age20212223
class_idgender
1F52.038.067.0NaN
M98.074.026.0NaN
2F53.046.087.0NaN
MNaN65.029.089.0
3F34.079.0NaN32.0
M78.085.032.0NaN
data.pivot_table(index=['class_id','gender'], 
    columns='age', values='score', aggfunc=np.max)
age20212223
class_idgender
1F52.038.067.0NaN
M98.074.026.0NaN
2F68.046.087.0NaN
MNaN65.029.089.0
3F34.079.0NaN32.0
M78.085.032.0NaN
r = data.pivot_table(index=['class_id','gender'], 
    columns='age', values='score', aggfunc=np.max,
    margins=True)
r
age20212223All
class_idgender
1F52.038.067.0NaN67
M98.074.026.0NaN98
2F68.046.087.0NaN87
MNaN65.029.089.089
3F34.079.0NaN32.079
M78.085.032.0NaN85
All98.085.087.089.098
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

YEGE学AI算法

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值