称列索引为特征/属性,每列为同质的;称行索引为记录的名称
数据运算与排序
1. df.sort_values排序
df.sort_values(排序依据索引列表, axis=0, ascending=True)
按指定的排序依据和轴向排序整行/列
accending:默认True为升序,False为降序
import pandas as pd
df = pd.DataFrame({'col1': ['A', 'A', 'B', 'D', 'C'],'col2': [2, 9, 8, 7, 4], 'col3': [1, 9, 4, 2, 3]})
print(df)
'''
col1 col2 col3
0 A 2 1
1 A 9 9
2 B 8 4
3 D 7 2
4 C 4 3
'''
# 依据col1排序
print(df.sort_values(['col1'], ascending=False))
'''
col1 col2 col3
3 D 7 2
4 C 4 3
2 B 8 4
0 A 2 1
1 A 9 9
'''
2. df.rank排名
df.rank(axis=0, method='average', ascending=True)
按轴向返回各元素的排名
method:处理相同值的排名时的方法:'average'平均排名,'min'最小排名,'max'最大排名,'first'出现顺序排名
accending:默认True为升序,False为降序
import pandas as pd
df = pd.DataFrame({'col1': ['A', 'A', 'B', 'D', 'C'],'col2': [2, 9, 8, 7, 4], 'col3': [1, 9, 4, 2, 3]})
print(df)
'''
col1 col2 col3
0 A 2 1
1 A 9 9
2 B 8 4
3 D 7 2
4 C 4 3
'''
# 使用默认的method='average'排序
print(df.rank())
'''
col1 col2 col3
0 1.5 1.0 1.0 # 出现相同,取几个排名的平均
1 1.5 5.0 5.0
2 3.0 4.0 4.0
3 5.0 3.0 2.0
4 4.0 2.0 3.0
'''# 使用method='min'排序
print(df.rank(method='min'))
'''
col1 col2 col3
0 1.0 1.0 1.0 # 出现相同,都取最小排名(max同理,都取最大(此处为2.0))
1 1.0 5.0 5.0
2 3.0 4.0 4.0
3 5.0 3.0 2.0
4 4.0 2.0 3.0
'''
# 使用method='first'排序
print(df.rank(method='first'))
'''
col1 col2 col3
0 1.0 1.0 1.0 # 出现相同,升序情况下先出现的名次靠前
1 2.0 5.0 5.0
2 3.0 4.0 4.0
3 5.0 3.0 2.0
4 4.0 2.0 3.0
'''
分位数的计算
np.percentile(ser1, 百分值列表) # 返回ndarray,百分值列表中数字1-100
np.quantile(ser1, 分位小数列表) # 返回ndarray,分位小数列表中数字0-1
ser1.quantile(分位小数列表) # 返回Series,分位小数列表中数字0-1
若ser1.quantile只计算一个分位点,则返回单个值
例题:
1.计算[1, 3, 5, 6, 8, 9, 15, 36]的三个四分位点的值。
首先排升序:[1, 3, 5, 6, 8, 9, 15, 36]
下标从0起: 0, 1, 2, 3, 4, 5, 6, 7
元素个数:N=8
0.25*(N-1)=0.25*7=1.75
0.25分位:a[1]+(a[2]-a[1])*0.75=3+(5-3)*0.75=3+1.5=4.5
0.5*(N-1)=0.5*7=3.5
0.5分位:a[3]+(a[4]-a[3])*0.5=6+(8-6)*0.5=6+1=7
0.75*(N-1)=0.75*7=5.25
0.75分位:a[5]+(a[6]-a[5])*0.25=9+(15-9)*0.25=10.5
故结果数组位[4.5, 7., 10.5]
import numpy as np
import pandas as pd
ser1 = pd.Series([36, 9, 3, 5, 6, 15, 8, 1])
print(np.percentile(ser1, [25, 50, 75]))
'''
[4.5, 7., 10.5]
'''
print(np.quantile(ser1, [0.25, 0.5, 0.75]))
'''
[4.5, 7., 10.5]
'''
print(ser1.quantile([0.25, 0.5, 0.75]))
'''
0.25 4.5
0.50 7.0
0.75 10.5
dtype:float64
'''
2. 计算[3, 5, 7, 1, 9, 2]的25%、75%分位点。

3.若已有import numpy as np,import pandas as pd,ser1=pd.Series([8,1,4,5,9,2]),则语句np.percentile(ser1,25)的执行结果应为___;而语句ser1.quantile(0.7)的执行结果应为___。
答案:2.5;6.5
练习题1
若有9个数据:15、1、8、16、13、5、9、20、3,请手工计算Q1、Q2、Q3、20%、90%等分位点上的数值。然后使用percentile和quantile函数验证手工计算结果的正确性。
手工计算:
升序:[1, 3, 5, 8, 9, 13, 15, 16, 20],N=9
0, 1, 2, 3, 4, 5, 6, 7, 8
0.25*(9-1)=2, Q1=a[2]=5
0.5*(9-1)=4, Q2=a[4]=9
0.75*(9-1)=6, Q3=a[6]=15
0.2*(9-1)=1.6,
20%分位点=a[1]+(a[2]-a[1])*0.6=3+(5-3)*0.6=3+1.2=4.2
0.9*(9-1)=7.2
90%分位点=a[7]+(a[8]-a[7])*0.2=16+(20-16)*0.2=16+0.8=16.8
import numpy as np
import pandas as pd
ser1 = pd.Series([15, 1, 8, 16, 13, 5, 9, 20, 3])
print(np.percentile(ser1, [25, 50, 75, 20, 90]))
'''
[5., 9., 15., 4.2, 16.8]
'''
print(np.quantile(ser1, [0.25, 0.5, 0.75, 0.2, 0.9]))
'''
[5., 9., 15., 4.2, 16.8]
'''
print(ser1.quantile([0.25, 0.5, 0.75, 0.2, 0.9]))
'''
0.25 5.0
0.50 9.0
0.75 15.0
0.20 4.2
0.90 16.8
dtype: float64
'''
数学统计
1. 描述性统计df.describe
df.describe(percentiles=None, inlcude=None, exclude=None)
返回一个DataFrame,包含df的描述性统计信息,包括:
仅数值列np.number时:非NaN元素个数count,均值mean,方差std,最小值min,25%分位数25%,50%分位数50%,75%分位数75%,最大值max
仅对象列np.object或'O'时:非NaN元素个数count,非重复元素个数unique,出现次数最多元素top,top出现的次数freq
'all'时:包括上面两种所有信息(先对象列有的统计行再数值列),其中数值列和对象列在count这行都有数据,其余在对方特有的统计行都为NaN
percentile:百分位点集合,默认为[0.25, 0.5, 0.75]
include:参与统计的列类型,默认None为数值列,np.number为数值列,np.object或'O'为对象类型列,'all'为全部列
exclude:排除掉的列类型
import pandas as pd
dict1 = {
'name':['小A', '小B', '小C', '小C'],
'score1':[50, 65, 65, 65],
'score2':[66, np.nan, 25, 25],
'score3':[53, np.nan, 26, np.nan]
}
df1 = pd.DataFrame(dict1)
print(df1)
'''
name score1 score2 score3
0 小A 50 66.0 53.0
1 小B 65 NaN NaN
2 小C 65 25.0 26.0
3 小C 65 25.0 NaN
'''
# 默认数值列统计
print(df1.describe())
'''
score1 score2 score3
count 4.00 3.000000 2.000000
mean 61.25 38.666667 39.500000
std 7.50 23.671361 19.091883
min 50.00 25.000000 26.000000
25% 61.25 25.000000 32.750000
50% 65.00 25.000000 39.500000
75% 65.00 45.500000 46.250000
max 65.00 66.000000 53.000000
'''
# 统计对象列
print(df1.describe(include='O'))
'''
name
count 4
unique 3
top 小C
freq 2
'''
# 统计全部列
print(df1.describe(include='all'))
'''
name score1 score2 score3
count 4 4.00 3.000000 2.000000
unique 3 NaN NaN NaN
top 小C NaN NaN NaN
freq 2 NaN NaN NaN
mean NaN 61.25 38.666667 39.500000
std NaN 7.50 23.671361 19.091883
min NaN 50.00 25.000000 26.000000
25% NaN 61.25 25.000000 32.750000
50% NaN 65.00 25.000000 39.500000
75% NaN 65.00 45.500000 46.250000
max NaN 65.00 66.000000 53.000000
'''
2. 求和df.sum
df.sum(axis=None, skipna=True, numeric_only=None)
返回一个Series,索引为df的列名,值为字符串列的字符串连接结果或数值列求和的值
skipna:跳过缺失值,默认为True
numeric_only:仅计算数值列,默认为None
import pandas as pd
dict1 = {
'name':['小A', '小B', '小C', '小C'],
'score1':[50, 65, 65, 65],
'score2':[66, np.nan, 25, 25],
'score3':[53, np.nan, 26, np.nan]
}
df1 = pd.DataFrame(dict1)
print(df1)
'''
name score1 score2 score3
0 小A 50 66.0 53.0
1 小B 65 NaN NaN
2 小C 65 25.0 26.0
3 小C 65 25.0 NaN
'''
print(df1.sum())
'''
name 小A小B小C小C # 字符串连接
score1 245 # 数值列求和
score2 116.0
score3 79.0
dtype: object
'''
数据分组df.groupby
df.groupby(分组依据)
1. 按列标签、列标签组合分组
gp1 = df.groupby(列标签) # 按列标签分组,该列数据相同的分到同一组
gp2 = df.groupby(列标签列表) # 按列标签组合分组,列组合数据相同的分到同一组
gp1.groups # 查看分组情况(查看groups属性)
import pandas as pd
dict1 = {
'n1':[50, 22, 25, 50, 50],
'n2':[50, 65, 65, 65, 50],
's1':['a', 'b', 'a', 'b', 'b'],
's2':['b', 'a', 'a', 'a', 'a'],
}
df1 = pd.DataFrame(dict1)
print(df1)
'''
n1 n2 s1 s2
0 50 50 a b
1 22 65 b a
2 25 65 a a
3 50 65 b a
4 50 50 b a
'''
# 按列标签分组
gp1 = df1.groupby('n1')
print(gp1.groups)
'''
{22: [1], 25: [2], 50: [0, 3, 4]}
'''
# 按列标签组合分组
gp2 = df1.groupby(['s1', 's2']) # ['s1', 's2']相同的分为一组
print(gp2.groups)
'''
{('a', 'a'): RangeIndex(start=2, stop=3, step=1), ('a', 'b'): RangeIndex(start=0, stop=1, step=1), ('b', 'a'): Index([1, 3, 4], dtype='int64')}
'''
2. 按字典映射分组
import pandas as pd
dict1 = {
'n1':[50, 22, 25, 50, 50],
'n2':[50, 65, 65, 65, 50],
's1':['a', 'b', 'a', 'b', 'b'],
's2':['b', 'a', 'a', 'a', 'a'],
}
df1 = pd.DataFrame(dict1)
print(df1)
'''
n1 n2 s1 s2
0 50 50 a b
1 22 65 b a
2 25 65 a a
3 50 65 b a
4 50 50 b a
'''
# 按字典映射分组
mapping = {0:'X', 1:'Y', 2:'X', 3:'Y', 4:'X'} # 索引0,2,4分到'X'组,索引1,3分到'Y'组
gp1 = df1.groupby(mapping)
print(gp1.groups)
'''
{'X': [0, 2, 4], 'Y': [1, 3]}
'''
3. 按序列分组
序列与行数(axis=0)/列数(axis=1)长度相同
import pandas as pd
dict1 = {
'n1':[50, 22, 25, 50, 50],
'n2':[50, 65, 65, 65, 50],
's1':['a', 'b', 'a', 'b', 'b'],
's2':['b', 'a', 'a', 'a', 'a'],
}
df1 = pd.DataFrame(dict1)
print(df1)
'''
n1 n2 s1 s2
0 50 50 a b
1 22 65 b a
2 25 65 a a
3 50 65 b a
4 50 50 b a
'''
# 按序列分组
lst = [5, 7, 6, 7, 5]
gp1 = df1.groupby(lst) # 第0、4行分到5组,1、3行分到7组,2行分到6组
print(gp1.groups)
'''
{5: [0, 4], 6: [2], 7: [1, 3]}
'''
4. 按行索引作用函数后结果分组
import pandas as pd
dict1 = {
'n1':[50, 22, 25, 50, 50],
'n2':[50, 65, 65, 65, 50],
's1':['a', 'b', 'a', 'b', 'b'],
's2':['b', 'a', 'a', 'a', 'a'],
}
df1 = pd.DataFrame(dict1)
print(df1)
'''
n1 n2 s1 s2
0 50 50 a b
1 22 65 b a
2 25 65 a a
3 50 65 b a
4 50 50 b a
'''
# 行索引作用函数后的值
gp1 = df1.groupby(lambda x: x+1 if x>2 else x**2)
print(gp1.groups)
'''
{0: [0], 1: [1], 4: [2, 3], 5: [4]}
'''
5. 按分组统计
在分组上可作用sum(), mean(), count(), size()等统计函数
注意区分:
只有groupby对象可以用size函数,df仅可用df.size返回属性
agg1.count():统计agg1分组中每组中每列上有几个非NaN元素
agg1.size():统计agg1分组中每组中有几个组员
import pandas as pd
dict1 = {
'n1':[50, 22, 25, 50, 50],
'n2':[50, 65, 65, 65, 50],
's1':['a', 'b', 'a', 'b', 'b'],
's2':['b', 'a', 'a', 'a', 'a'],
}
df1 = pd.DataFrame(dict1)
print(df1)
'''
n1 n2 s1 s2
0 50 50 a b
1 22 65 b a
2 25 65 a a
3 50 65 b a
4 50 50 b a
'''
# 按序列分组
lst = [5, 7, 6, 7, 5]
gp1 = df1.groupby(lst) # 第0、4行分到5组,1、3行分到7组,2行分到6组
print(gp1.groups)
'''
{5: [0, 4], 6: [2], 7: [1, 3]}
'''
print(gp1.count())
'''
n1 n2 s1 s2
5 2 2 2 2
6 1 1 1 1
7 2 2 2 2
'''
print(gp1.size())
'''
5 2
6 1
7 2
dtype: int64
'''
print(gp1['n1'].mean())
'''
5 50.0
6 25.0
7 36.0
Name: n1, dtype: float64
'''
print(gp1['n2'].sum())
'''
5 100
6 65
7 130
Name: n2, dtype: int64
'''
数据聚合df.agg
1. 所有行列通过同一函数列表聚合
df.agg(函数列表, axis=0) # 通过函数在指定轴上完成聚合操作,默认处理全部行/列,若numeric_only设True则自动跳过非数值行/列
import pandas as pd
import numpy as np
dict1 = {
'n1':[50, 22, 25, 50, 50],
'n2':[50, 65, 65, 65, 50]
}
df1 = pd.DataFrame(dict1)
print(df1)
'''
n1 n2
0 50 50
1 22 65
2 25 65
3 50 65
4 50 50
'''
# 进行聚合,带引号的表示DataFrame的函数,不带的表示通用函数或np的函数
print(df1.agg(['sum', 'min', sum, np.min]))
'''
n1 n2
sum 197 295
min 22 50
sum 197 295
min 22 50
'''
2. 在不同行列上通过不同函数聚合
使用键值对为列名:函数列表的字典来指定
import pandas as pd
import numpy as np
dict1 = {
'n1':[50, 22, 25, 50, 50],
'n2':[50, 65, 65, 65, 50]
}
df1 = pd.DataFrame(dict1)
print(df1)
'''
n1 n2
0 50 50
1 22 65
2 25 65
3 50 65
4 50 50
'''
# n1上sum、min,n2上mean
print(df1.agg({'n1':['sum', 'min'], 'n2':['mean']}))
'''
n1 n2 # 未做该函数的,该位置标NaN
sum 197.0 NaN
min 22.0 NaN
mean NaN 59.0
'''
3. 在groupby对象上使用agg
被作为分组键的列不参与后续聚合操作
gp1.agg(函数字典或列表, axis=0)
import pandas as pd
dict1 = {
'n1':[50, 22, 25, 50, 50],
'n2':[50, 65, 65, 65, 50],
's1':['a', 'b', 'a', 'b', 'b'],
's2':['b', 'a', 'a', 'a', 'a'],
}
df1 = pd.DataFrame(dict1)
print(df1)
'''
n1 n2 s1 s2
0 50 50 a b
1 22 65 b a
2 25 65 a a
3 50 65 b a
4 50 50 b a
'''
# 按列标签分组
gp1 = df1.groupby('n1')
print(gp1.groups)
'''
{22: [1], 25: [2], 50: [0, 3, 4]}
'''
# 对分组进行聚合操作
print(gp1.agg(['sum', 'count']))
'''
n2 s1 s2 # n1作为分组键不参与运算。出现多级列索引
sum count sum count sum count
n1
22 65 1 b 1 a 1
25 65 1 a 1 a 1
50 165 3 abb 3 baa 3
'''
4. 数据聚合gp.apply
import pandas as pd
import numpy as np
dict1 = {
'n1':[50, 22, 25, 50, 50],
'n2':[50, 65, 65, 65, 50],
's1':['a', 'b', 'a', 'b', 'b'],
's2':['b', 'a', 'a', 'a', 'a'],
}
df1 = pd.DataFrame(dict1)
print(df1)
'''
n1 n2 s1 s2
0 50 50 a b
1 22 65 b a
2 25 65 a a
3 50 65 b a
4 50 50 b a
'''
# 行索引作用函数后的值
gp1 = df1.groupby(lambda x: x+1 if x>2 else x**2)
print(gp1.groups)
'''
{0: [0], 1: [1], 4: [2, 3], 5: [4]}
'''
# 使用apply对分组应用函数进行聚合
print(gp1[['n1', 'n2']].apply(np.sum)) # 使用np.sum
'''np.sum→全局总和(展平后求和)→一维Series
0 100
1 87
4 205
5 100
dtype: int64
'''
print(gp1[['n1', 'n2']].apply(lambda x: x.sum())) # 使用lambda表达式
'''df.sum()→逐列总和→二维DataFrame
n1 n2
0 50 50
1 22 65
4 75 130
5 50 50
'''
Pandas读写数据
1. 读写csv文件
(1) 写入df.to_csv
df.to_csv(文件路径字符串, sep=',', columns=None, header=True, index=True)
文件路径字符串:如同目录下文件'./Scores.csv'
sep:分隔符,默认为逗号
columns:需要写入的列
header:是否写入列名,默认为True
index:是否写入行索引,默认为True
(2) 读取pd.read_csv
df = pd.read_csv(文件路径字符串, sep=',', header=0, names=None)
header:指定第几行为列名,并舍弃该行之前的数据。默认第一行(header=0)。若保存时未保存列名,第一行就是数据,那么可以指定header=None不指定列名
names:重命名列名,可指定新的列名列表
import pandas as pd
dict1 = {
'name':['小A', '小B', '小C', '小C'],
'score1':[50, 65, 65, 65],
'score2':[66, np.nan, 25, 25],
'score3':[53, np.nan, 26, np.nan]
}
df1 = pd.DataFrame(dict1)
print(df1)
'''
name score1 score2 score3
0 小A 50 66.0 53.0
1 小B 65 NaN NaN
2 小C 65 25.0 26.0
3 小C 65 25.0 NaN
'''
# 只保存分数列,保存行索引,不保存列名
df1.to_csv('./Score.csv', columns=['score1', 'score2', 'score3'], header=False)
# 不选择列名行,指定新列名,读取
df2 = pd.read_csv('./Score.csv', sep=',', header=None, names=['分数1', '分数2', '分数3'])
print(df2)
'''
分数1 分数2 分数3
0 50 66.0 53.0
1 65 NaN NaN
2 65 25.0 26.0
3 65 25.0 NaN
'''
读写excel文件
(1) 写入df.to_excel
df.to_excel(文件路径字符串, sheet_name='sheet1', columns=None, header=True, index=True)
sheet_name:默认写入在sheet1工作表,可指定到其它表
columns:需要写入的列
header:是否写入列名,默认为True
index:是否写入行索引,默认为True
(2) 读取pd.read_excel
df = pd.read_excel(文件路径字符串, sheet_name=0, header=0, index_col=None, names=None)
header:指定第几行为列名,并舍弃该行之前的数据。默认第一行(header=0)。若保存时未保存列名,第一行就是数据,那么可以指定header=None不指定列名
sheet_name:默认0读取第一张表,设为None读取全部表,可传入列表读取多个表
index_col:指定某列为行索引
names:重命名列名,可指定新的列名列表
import pandas as pd
dict1 = {
'name':['小A', '小B', '小C', '小C'],
'score1':[50, 65, 65, 65],
'score2':[66, np.nan, 25, 25],
'score3':[53, np.nan, 26, np.nan]
}
df1 = pd.DataFrame(dict1)
print(df1)
'''
name score1 score2 score3
0 小A 50 66.0 53.0
1 小B 65 NaN NaN
2 小C 65 25.0 26.0
3 小C 65 25.0 NaN
'''
# 保存行列索引
df1.to_excel('./score.xlsx')
# 直接读取,不指定行列索引
df2 = pd.read_excel('./score.xlsx')
print(df2)
'''
Unnamed: 0 name score1 score2 score3 # 原行索引被作为一列数据读出,下一段代码解决该问题
0 0 小A 50 66.0 53.0
1 1 小B 65 NaN NaN
2 2 小C 65 25.0 26.0
3 3 小C 65 25.0 NaN
'''
# 指定第0列为行索引,读取的几列重命名列索引
df3 = pd.read_excel('./score.xlsx', index_col=0, names=['姓名', '分数1', '分数2', '分数3'])
print(df3)
'''
姓名 分数1 分数2 分数3
0 小A 50 66.0 53.0
1 小B 65 NaN NaN
2 小C 65 25.0 26.0
3 小C 65 25.0 NaN
'''
练习题2
从“国民经济核算季度数据.npz”文件中读取2000年第一季度到2017年第一季度的所有数据并存储在ndarray对象中。
(1) 创建一个DataFrame对象,其数值数组不包含原ndarray对象的第0列和最后一行数据(即不包含“序号”那一列数据和“2017年第一季度”那一行数据);其列索引为:['时间', 'GDP', '一产', '二产', '三产', '农业', '工业', '建筑', '批发', '交通', '餐饮', '金融', '房地产', '其他'];
(2) 按“年份”分组(需提取“时间”那一列数据中包含的“年份”信息,提出来按一个列表)。在此基础上,计算每年总的GDP,三个产业以及各行业的全年GDP;(“年份”的跨度为:2000~2016年。)
(3) 在每个年份上,计算三个产业的全年GDP之和以及各行业的全年GDP之和;并分别以“产业GDP之和”和“行业GDP之和”为列索引名将计算结果添加到对应的DataFrame对象中。
(4) 在每个年份上,分别计算“产业GDP之和”之于年“GDP”(年“GDP”就是第(2)小题所说的每年总的GDP,也就是每年4个季度的GDP之和)以及“行业GDP之和”之于年“GDP”的相对误差,计算公式为(以“产业……”为例):
(“产业GDP之和”-“GDP”)/“GDP”
然后,分别以“产业之和的误差”和“行业之和的误差”为列索引名将计算结果添加到对应的DataFrame对象中;
(5) 抽取并输出“GDP”,“产业GDP之和”,“产业之和的误差”,“行业GDP之和”,“行业之和的误差”这几列数据,其部分显示结果如下所示:
GDP 产业GDP之和 产业之和的误差 行业GDP之和 行业之和的误差
2000 100280.1 100280.0 -9.972068e-07 100280.0 -9.972068e-07
2001 110863.1 110863.1 0.000000e+00 110863.1 0.000000e+00
2002 121717.4 121717.4 -1.195549e-16 121717.5 8.215752e-07
…… …… …… …… …… ……
2015 689052.0 689052.2 2.902539e-07 689051.9 -1.451269e-07
2016 744127.2 744127.3 1.343856e-07 744127.2 0.000000e+00
代码检验是不是所有误差都在万分之一以内,并以此来判定“国民经济核算季度数据.npz”文件中的数据是不是“有效”的;
(6) 如果数据是有效的,将第(2)小题分组计算所得的DataFrame对象的行索引命名为“年份”。然后再将该数据(包括行索引和列索引)存储在“GDP年度数据.csv”文件中。
# 本人思路,仅供参考
import numpy as np
import pandas as pd
arr1 = np.load('./国民经济核算季度数据.npz', allow_pickle=True)
columns1 = arr1['columns']
data = arr1['values']
print(columns1)
print(data)
# (1)
columns2 = ['时间', 'GDP', '一产', '二产', '三产', '农业', '工业', '建筑', '批发', '交通', '餐饮', '金融', '房地产', '其他']
df = pd.DataFrame(data[:-1, 1:], columns=columns2)
print('(1)')
print(df)
# (2)
lst = [item[0:4] for item in df['时间']]
print('(2)')
print('分组列表为:')
print(lst)
gp1 = df.groupby(lst)
print('根据分组列表分组如下:')
print(gp1.groups)
df_year = gp1.agg('sum').drop(columns='时间')
print('年数据df如下:')
print(df_year)
# (3)
df2 = df_year.copy()
df2['产业GDP之和'] = df2[['一产', '二产', '三产']].sum(axis=1)
df2['行业GDP之和'] = df2.loc[:, '农业':'其他'].sum(axis=1) # 注意这里必须是[:, '农业':'其他']而不能是[:, '农业':],后者会将刚刚添加的产业GDP之和列也计算进去
print('(3)')
print(df2)
# (4)
def div(ser1, ser2):
ser_r = (ser1 – ser2) / ser2
return ser_r
df2['产业之和的误差'] = div(df2['产业GDP之和'], df2['GDP'])
df2['行业之和的误差'] = div(df2['行业GDP之和'], df2['GDP'])
print('(4)')
print(df2)
# (5)
usable = False
print('(5)')
print('抽取数据如下:')
print(df2[['GDP', '产业GDP之和', '产业之和的误差', '行业GDP之和', '行业之和的误差']])
if all(df2['产业之和的误差'].abs() < 0.0001) and all(df2['行业之和的误差'].abs() < 0.0001):
print('数据有效')
usable = True
else:
print('数据无效')
# (6)
print('(6)')
if usable:
df_year.index.name = '年份'
df_year.to_csv('./GDP年度数据.csv', index=True, header=True)
print('数据已保存到./GDP年度数据.csv中')
else:
print('数据无效,未保存')
练习题3
“mtcars.csv”文件中存储了某些汽车型号的特征数据,包括name(汽车型号),cyl(汽缸数),carb(化油器),mpg(油耗),hp(马力)等特征。
(1) 使用pandas读取mtcars数据集,输出数据集的大小(shape);
(2) 抽取并输出5个数值型特征的描述性统计信息,自行解释这些数据的含义;
(3) 按cyl和carb进行分组,计算并输出hp列每个分组所包含的有效数据的个数、每个分组的最大马力、每个分组的最小马力以及mpg列每个分组所包含的有效数据的个数、每个分组的平均油耗。
# 本人思路,仅供参考
import pandas as pd
# (1)
df = pd.read_csv('./mtcars.csv')
print('(1)')
print('原数据集为:')
print(df)
print('原数据集大小为:')
print(df.shape)
# (2)
print('(2)')
print(df[['cyl', 'carb', 'mpg', 'hp', 'qsec']].describe())
# (3)
gp = df.groupby(['cyl', 'carb'])
print('(3)')
print('分组结果为:')
print(gp.agg({'hp':['count', 'max', 'min'], 'mpg':['count', 'mean']}))
练习题4
“Scores.xlsx”文件中存储了计算机专业2020级全部同学(分属3个不同的班),在2021学年秋季学期3门公共课的考试成绩,包括学号、姓名、班号、3门公共课的成绩(为了简单起见,分别用C1,C2,C3表示)等信息。由于疫情原因,有一部分同学没有参加某些课程的期末考试,对应成绩用NaN表示。其列表化的部分数据如下所示:
学号 姓名 班号 C1 C2 C3
2020003 李珏 202001 76.0 88.0 67.0
…… …… …… …… ……
2020038 吴琼 202002 74.0 96.0 92.5
2020039 颜敏 202002 88.0 NaN 73.0
…… …… …… …… ……
2020072 钱思思 202003 55.0 97.0 54.0
…… …… …… …… ……
(1) 使用pandas读取“Scores.xlsx”文件,构造原始DataFrame对象;
(2) 删除所有成绩中含为NaN的学生信息(不作为有效信息计入最终的统计),并重置行索引;
(3) 在(2)的基础上,计算每个同学3门课程成绩的平均分,并将其作为新的一列(列索引为aver)添加到(2)的结果中。
(4) 在(3)的基础上,计算并输出每个班参与统计的同学总数,每个班的最高平均成绩,每个班的最低平均成绩,每个班平均成绩的均值。
# 本人思路,仅供参考
import numpy as np
import pandas as pd
# (1)
df = pd.read_excel('Scores.xlsx')
print('(1)')
print('原df为:')
print(df)
# (2)
df.dropna(how='any', ignore_index=True, inplace=True)
print('(2)')
print(df)
# (3)
df['aver'] = df.loc[:, 'C1':'C3'].mean(axis=1)
print('(3)')
print(df)
# (4)
gp = df.groupby('班号')
print(gp['aver'].agg(['count', 'max', 'min', 'mean']))





