pandas_知识总结_基础

# Pandas 知识点总结
# Pandas数据结构:Series 和 DataFrame
import pandas as pd
import numpy as np

# 一,Series:
# 1, 创建 Series  pd.Series(列表或字典)

s_obj = pd.Series([4,7,-5,3])
s_obj

sdata={'Ohio':35000,'texas':71000,'Oregon':16000,'Utah':1000}
s_obj3=pd.Series(sdata)  # 产生一个按【键】排好序的字典。
s_obj3
# 可以对键重新定义,当新定义的键在原字典中不存在时,Series处理这个缺失值为NaN。
# 当原来的字典中的键不存在于新定义的索引列表中时,这个键值对就会被排除掉。
s_obj4=pd.Series(sdata,index=["Tom",'Ohio','Ivan','Utah'])
s_obj4
s_obj.values  # Series的值数组     array([ 4,  7, -5,  3], dtype=int64)
s_obj.index   # Series的索引对象   RangeIndex(start=0, stop=4, step=1)

# 2, 自定义索引:
# 在创建序列时,给 index参数指定索引列表
s_obj2=pd.Series([4,7,-5,3],index=['d','b','a','c'])
# 使用 Series_obj.index属性,按【位置】赋值创建/改变索引:
s_obj2.index=['m','b','a','d']  # 长度必须与 序列的 size一致,否则报错。
s_obj2
# m    4
# b    7
# a   -5
# d    3
# dtype: int64

# 3, 使用索引访问和修改序列元素
s_obj[2]     # -5  
s_obj2['a']  # -5  使用行标签进行索引
s_obj2[2]    # -5  使用行号进行索引
s_obj2[2]=0  
s_obj2  
# m    4
# b    7
# a    0
# d    3
# dtype: int64

# 4, 对Series对象使用 Numpy 函数或 Numpy 风格的各种操作(如根据布尔型数组进行过滤,与标量相乘,或者应用数学函数),都会保留索引与值
# 之间的连接关系:

s_obj2[obj2>0] #以布尔型数组进行索引
s_obj2*2
np.exp(obj2)  # 计算各元素的以e为底的指数


# 5, 判断索引是否存在于序列中:
print('Yes') if 'b' in s_obj2 else print('No')
print('Yes') if 'b' in s_obj2.index else print('No')
print('Yes') if 'e' in s_obj2 else print('No') 
print('Yes') if 'e' in s_obj2.index else print('No') 

# 6, 检验缺失数据:isnull()  notnull()函数 
# 既可以作为pandas的顶层函数,也可以作为 Series实例对象调用的方法。
# 对序列中的每个元素进行判断,返回与原数组长度相同的 布尔类型 Series对象。
# 在后面的章节中会深入的讨论如何处理缺失数据。

pd.isnull(Series_obj)  等同于 Series_obj.isnull()
pd.notnull(Series_obj) 等同于 Series_obj.notnull()   


# 7, Series的索引自动对齐:
# 比如进行数学计算时,相同索引的元素进行计算,索引不相同的引入 NaN
# Series的索引自动对齐功能和数据库的join操作是很相似的。
obj3+obj4


# 8, series_obj.name 属性和 Series_obj.index.name 属性:
# 可以修改这两个属性(默认为None),他们往往和pandas的其他重要功能集成在一起。
print(obj4.name)         # None
print(obj4.index.name)   # None
obj4.name="population"   # 人口
obj4.index.name="state"  # 州
obj4


# 二,DataFrame

# 表示矩阵数据表,包含已经排序的列集合,每一列可以是不同的值类型(数值,字符串,布尔值等)。
# 既有行索引,也有列索引。
# 可以被视为共享相同索引的 Series的字典。
# 数据被存储为一个以上的二维块,而不是列表,字典或其他一维数组的集合。
# Note: 尽管 DataFrame是二维的,但可以利用分层索引在DataFrame中展现更高维度的数据。分层索引是pandas中一种更为高级的数据处理特性。
# DataFrame 既可以创建而来,也可以由其他数据类型转化而来。


# 1,创建 DataFrame
# DataFrame 构造函数的有效输入:

# 二维数组 2d ndarray                数据矩阵,行列的索引标签是可选参数  
# 数组,列表,元组,序列构成的字典      每个序列成为 DataFrame 的一列,所有的序列必须长度相等 
# Numpy 结构化/记录化数组            与数组构成的字典一致
# Series 构成的字典                  每个 Series为一列,Series的索引合并为行索引,也可以显式的传递索引
# 字典构成的字典(嵌套字典)          每一个内部字典形成一列,键联合起来形成结果的行索引 
# 字典或Series构成的列表             列表中的一个元素形成 DataFrame的一行,字典的键 或Series索引联合起来形成 DataFrame的列标签
# 列表或元组构成的列表               与 2d ndarray的情况一致

# 其他DataFrame                     如果不显式传递索引,则会使用原 DataFrame 的索引
# Numpy MaskedArray                 与 2d ndarray的情况类似,但隐藏值会在结果DataFrame 中成为 NA/缺失值

# 示例:
# 1-1)pd.DataFrame(dict_mixvalu)
data={
    'name':np.array(['张三','李四','王五','小明']),   # 字典的值是 数组
    'sex':('female','female','male','male'),        # 字典的值是 元组
    'year':[2001,2001,2003,2002],                   # 字典的值是 列表
    'city':pd.Series(['北京','上海','广州','深圳'])  # 字典的值是 序列
}
df=DataFrame(data3)
df

# 1-2)pd.DataFrame(嵌套字典)  # 外层字典的键为 列索引,内层字典的键为 行索引
data2={
    'sex':{'张三':'female','李四':'female','王五':'male'},
    'city':{'张三':'北京','李四':'上海','王五':'广州'}
}

df02=DataFrame(data2)
# df02=DataFrame(data2,index=['老大','李四','王五'])   # 显式地指定行/列索引的顺序或改变 行/列数据。
# df02=DataFrame(data2,index=['老大','李四','王五'],columns=['sex','city','newcolumn'])
df02

1-7) 使用列表或元组构成的嵌套列表创建 DataFrame 数据
1-8) 使用字典列表创建 DataFrame 数据 
1-9) 使用Series对象创建 DataFrame 数据
1-10) 使用 2dndarray 创建 DataFrame 数据


# 2, 查看 行,列索引对象:
df02.columns  
df02.index

# 3, 指定列索引列表,对列索引进行排序:
# 虽然上面的df都是按创建时的code 顺序对列进行排列的,但由于字典是无序的,所以为了安全起见,我们创建DataFrame时手动指定修改 列的顺序:
from pandas import DataFrame
import numpy as np
data={
    'name':np.array(['张三','李四','王五','小明']),
    'sex':np.array(['female','female','male','male']),
    'year':np.array([2001,2001,2003,2002]),
    'city':np.array(['北京','上海','广州','深圳'])
}
df02=DataFrame(data,columns=['name','year','sex','city'])  
df02

# 4, 指定行索引列表(没有指定行索引的情况下,默认的行索引是从0到N-1(N为数据长度))
df03=DataFrame(data,columns=['name','year','sex','city'],index=['a','b','c','d'])  # 语法
df03

# 当指定的【列】索引在传入的data字典中不存在时,将会以缺失值NaN处理:
# 如果少指定了某【列】,生成的DataFrame对象就不含此列数据。
# 如果多指定了【行】或少指定了行,就会报错。
df03=DataFrame(data,columns=['name','year','sex','city','job'],index=['a','b','c','d'])  # 语法
df03

# 5, 对 DataFrame的行和列进行索引:
# 索引 DataFrame的【列】   返回 Series对象: 
df['sex']
df.sex

# 索引 DataFrame的【行】   返回 Series对象:
df.loc['李四']
df.iloc[1]

# 6,给列赋值 和 增加新的列
df04['job']='Data Analysis'      # 将一个值赋值给一列
df04['job']=np.arange(4.)        # 将一个与列等长度的ndarray数组赋值给一列
df04['job']=['Data Analysis']*4  # 将一个与列等长度的列表赋值给一列

val=pd.Series(['Data Analysis dev','Data Analysis im','Data Analysis ba'],index=['马','李','张'])
df04['job']=val  # 将一个长度<=列长度的 Series对象赋值给一列, 缺失值处理为NAN,按照 DataFrame的索引排列

val=pd.Series(['band 6A','band 8B','band 7B'],index=['马','李','王'])
df04['band']=val  # 创建一个新的列。


# 7, del 关键字 删除DataFrame的列  
# 示例:先增加一列,再删掉:
df04['new']=df04.sex=='female' 
del df04['new']


# 8, 复制列得到 Series对象:
series_copy=df04['sex'].copy()
series_copy[2]='haha'  # 对其修改不影响 df04的 sex列

# 9, DataFrame 的转置   dataframe_obj.T
df04.T

# 10, 修改列索引和行索引的 name属性:
df04.index.name='Name'
df04.columns.name='Infor'

# 11, 查看 DataFrame的 index, column, values属性:
df04.index    # 一维 RangeIndex对象
df04.columns  # 一维 Index对象
df04.values   # 二维 ndarray数组

# 12, 索引对象的操作方法:
# pandas 中的索引对象是用于存储轴标签和其他元数据的 (例如轴名称或标签)。

data={
    'name':np.array(['张三','李四','王五','小明']),
    'sex':('female','female','male','male'),
    'year':[2001,2001,2003,2002],
    'city':('北京','上海','广州','深圳')
}
df=DataFrame(data)

# 1) 索引对象
df.index

# 2) 索引对象不可通过被索引的方式更改,强改会报错:
index=df.index     index[1]=0    # 报错
col = df.columns   col[1]='a'    # 报错
# 可通过如下方式修改 DataFrame的【行】索引:
df.index=['a','b','c','d']
# df.column=['c1','c2','c3','c4']  # 列索引不允许这样修改

# 3)对 DataFrame的行列索引的 name属性赋值/修改:
df.index.name='infor item'
df.columns.name='details'


# 三,pandas 索引操作

# (1)讲解 Series 和 DataFrame 的索引操作的方法
# (2)与 Excel 数据类比,讲解 DataFrame 数据的选取与操作

# 1) 修改行或列的索引标签:
# 更改行索引,可以使用 df.index=[新索引列表],或 df.rename(index={'c':'cc'}, inplace = True)
# 更改列索引,可以使用 df.rename(columns={'COMPANY':'公司'}, inplace = True) 

# 2) 重新索引 se.reindex([]); df.reindex(index=[],columns=[]):
# 用来引入新的行或列,不是用来按位置更改索引的名称,因为引入新的索引名称,会带来 NaN行或 NaN列.

# 2-1)Series 重新索引: se_obj.reindex(新索引列表[,method='ffill'])  返回一个新的 Series对象,不改变原来的 Series.
# 其中 method 参数可以缺省,缺省时,新索引列表中新引入的索引对应的元素值为 NaN,
# method='ffill'或'pad' 指元素值与前后一行相同(向前填充),method='bfill' 或'pad' 指元素值与前一行相同(向后填充)。

s_obj=Series([1,2,3,4],index=['a','c','d','f'])
s_obj2=s_obj.reindex(['a','c','m','d','e'])   # 没有使用原来的索引 f,新引入了索引 m,e
s_obj2

a    1.0
c    2.0
m    NaN
d    3.0
e    NaN
dtype: float64
    
s_obj3=s_obj.reindex(['a','c','m','d','e'],method='ffill')   # 使用 f的值填充 m,使用d的值填充 e
s_obj3

a    1
c    2
m    4
d    3
e    3
dtype: int64
    
s_obj4=s_obj.reindex(['a','c','m','d','e'],method='bfill')   # 使用 NaN值填充 m,使用f的值填充 e
s_obj4    
a    1.0
c    2.0
m    NaN
d    3.0
e    4.0
dtype: float64
    
# 2-2)DataFrame 重新索引:返回新的 DataFrame, 不改变原有 DataFrame
df=DataFrame(np.arange(9).reshape((3,3)),index=['a','c','d'],columns=['name','id','sex'])
df2=df.reindex(index=['a','b','c','d'],fill_value=0)   # 重新索引,引入一个新的行
df3=df.reindex(columns=['name','id','gender','job'],fill_value=0)   # 重新指定列索引要使用 columns关键字
# 当 fill_value参数缺省或 fill_value=None时,引入的新行或列对应的元素值是 NaN


# 3, 替换默认索引 df.set_index(要使用的某个列的标签):(针对 DataFrame)     返回新的 DataFrame, 不改变原来的 DataFrame
df2=df.set_index('name')  # 使用 name 这列来替代默认行索引,'name'变成了行索引的index.name 属性值。

# 4, 更新默认索引 df2.reset_index([drop=True])
df3=df2.reset_index([drop=True])

# 5, 数据的索引和选取:
# 5-1)Series 的数据选取:
# 行号索引:      Series_obj[n]
# 行标签索引:    Series_obj['a']
# 行号切片索引    Series_obj[n1:n2]      注意,与 Python列表相同:    含左不含右
# 行标签切片索引  Series_obj['i1':'in']  注意,与 Python列表不同之处: 含左也含右!!!
# 布尔索引       Series_obj[Series_obj==2]

# 对选取元素的值的更改,会影响到原来的 Series或 DataFrame。
Series_obj[2]=6  

# 5-2)DataFrame 的数据选取:
data={
    'name':np.array(['张三','李四','王五','小明']),
    'sex':('female','female','male','male'),
    'year':[2001,2000,2003,2002],
    'city':pd.Series(['北京','上海','广州','深圳'])
}
df=DataFrame(data)
df2=df.set_index('name')
df2

# DataFrame 行列 选取总结:

# df2['王五']   # 报错
# df2[1]        # 报错
# 多行:
# df2.[['张三','王五']]  # 报错
# df2.[[1,3]]           # 报错

# 为了防止弄混,DataFrame选取多行时,一律使用 loc和 iloc:(当使用切片时,不使用 loc iloc也是允许的)

# 获取单个元素:
df.loc['王五',2] 
df.iloc[2,2] 
df.loc[df['sex']=='female','female'] ='f'   # df['sex']=='female' 是一个布尔序列,布尔序列可以作为行索引。

# 单行:
df.loc['王五']   
df.iloc[1]  

# 多行:
df.iloc[0:2] 
df.loc['李四':'王五']
df.loc[['张三','王五']]  
df.iloc[[1,3]] 

# 单列:
df.year     # 按属性选取
df['year']  # 按列索引标签选取

# 多列:(不可使用切片)
df[['year','name']]

# 选取行列子集:
df.loc[df.index[0:2], ['name','city']]
df.loc[df.index[[0,2]], ['name','city']]
df.iloc[df.index[[0,2]], [0,2]]
df=df.loc[df['status']!="Cancelled",['CNUM','status',"Tax"]]  # 选取 status列中的值不是cancelled的'CNUM','status',"Tax"三列数据。类似excel里的筛选。

# 布尔选择
# 与数组布尔型索引相似:!=  ~  & |
df['sex']=='female'      # 对某一列进行条件判断,返回布尔型 Series
df[df['sex']=='female']  # 返回符合条件的行列子集
df[df['sex']=='female' & df['year']==2001] # 必须使用括号
df[(df['sex']=='female') & ~(df['year']==2001)] 
df[(df['sex']=='female') & (df['year']!=2001)] 
df[(df['sex']=='female') | (df['year']==2002)] 

# 使用 loc/iloc 和布尔索引确定 符合条件的元素
df.loc[df['sex']=='female','female'] ='f'  # 这样 sex为 female对应的的sex列的值变为 f
iris_df.loc[iris_df['class'] == 'versicolor', 'class'] = 'Iris-versicolor'

# 对索引出来的数据进行修改,会影响到原来的数据结构
df[df['sex']=='female'] ='f'      # 这样 sex为 female的整行数据都会变为 f
df.loc[df['sex']=='female','female'] ='f'  # 这样 sex为 female对应的的sex列的值变为 f
df['year'] = 2010

# 要想索引出来的数据独立使用,不影响原来数据结构,就要使用 .copy()
df2=df[df['sex']=='female'].copy()
df2.year=2030


# 6, DataFrame的增,删,改,查(即索引)
# 【 不会改变原来的 DataFrame,返回一个新的 DataFrame】

# 6-1)查  即上面的   5, 数据的索引和选取:
# 6-2)增
# 6-2-1)对行的增加: df.append(new_data,ignore_index=True)    增加一行数据
import numpy as np
from pandas import DataFrame,Series
import pandas as pd
data={
    'name':np.array(['张三','李四','王五','小明']),
    'sex':('female','female','male','male'),
    'year':[2001,2000,2003,2002],
    'city':pd.Series(['北京','上海','广州','深圳'])
}
df=DataFrame(data)
new_data={
    'name':"Tom",
    'sex':'male',
    'year':2007,
    'city':'南京'
}
df2=df.append(new_data,ignore_index=True)   # 返回一个新的 DataFrame, 不影响原来的。ignore_index=True参数是必须要有的
df2

# 6-2-2) 对列的增加: 对列的增加删除和修改见 : 二 DataFrame  6,给列赋值 和 增加新的列

# 6-3)删
# 删除行:new_df=df.drop(2,axis=0)       或 # 删除行:new_df=df.drop('i3',axis=0)  其中 axis=0可以缺省
# 删除列:new_df=df.drop('city',axis=1)  
# 删除原数据的列: del df['city'](会影响原数据)

# 6-4)改  
# 当参数inplace=True时,会原地修改,当inplace=False或缺省时,不会影响原数据,返回一个新的数据。
# 这里的修改是指 对行列索引标签的修改,通过 df.rename()函数,可完成由于某些原因导致的标签录入错误的问题:
new_df4=new_df3.rename(index={'王五':'王老五','小明':'马六'},columns={'sex':'gender'})
new_df3.rename(index={'王五':'王老五','小明':'马六'},columns={'sex':'gender'},inplace=True) # 可在原数据上进行修改


# 四,pandas 算术运算 

# 参与运算的 各个 Series 的size大小任意。
# 参与运算的 各个 DataFrame 的行数必须相同。

# 1, Series 算术运算
# 有共同索引的元素才会进行算术运算,如果没有,则引入 NaN --对齐操作
from pandas import Series,DataFrame
S1=Series([2.1,5,-3,0.2,0.3],index=['a','c','d','f','g'])
S2=Series([3.5,1.5,-2,0.5],index=['a','b','d','e'])  # 共同索引为 'a','d'
S1+S2
# S1.add(S2,fill_value=0)  # 缺失值 按 0 计算  

# 2, DataFrame 算术运算
# 对于 DataFrame数据,对齐操作会同时发生在行和列上
df1=DataFrame(np.arange(9).reshape(3,3),index=['apple','banana','tea'],columns=['a','b','c'])
df2=DataFrame(np.arange(9).reshape(3,3),index=['apple','banana','coco'],columns=['a','b','d'])
df1+df2  # 运算返回的结果包含了参与运算的 df的所有的列。  行和列都符合才可以计算。
# df1.add(df2,fill_value=0)   # 行或列只要有一个符合,就可以计算,缺失值按 0计算,行和列都不符合才是 NaN

# 3, DataFrame 和 Series的 算术运算:
# 要求 Series的【行索引】和 DataFrame的【列索引】要一致。
S1=Series([2,3,4],index=['a','b','c'])
df1=DataFrame(np.arange(9).reshape(3,3),index=['apple','banana','tea'],columns=['a','b','c'])
df1+S1 # df的 a列+2 b列+3,c列+4

df1=DataFrame(np.arange(9).reshape(3,3),index=['apple','banana','tea'],columns=['a','b','c'])
s1=df1.loc['apple']  # 取 DtaFrame的单行,这样取得的 Series的索引为 DataFrame的列索引
df1+s1


# 五, 函数应用与映射

# 定义函数或 Lambda表达式,然后应用到 pandas数据中对数据进行较为复杂的函数运算:
# 有三种使用自定义函数的datafrom方法: 参数 f 为自定义函数,也可以是lambda表达式
# 1, se.map(f) 函数              将函数套用在每个 Series 元素上
# 2, df.aplly(f,axis=1)函数      将函数套用在 DataFrame的行与列上,若 axis缺省,则默认axis=0
# 3, df.applymap(f)函数          将函数套用在 DataFrame的每个元素上

# 注意,1) lambda 表达式里如果使用判断表达式,if和 else必须要成对出现!、
#       2) 上面几个映射函数,都不改变原来数据结构,返回新的数据结构。

# se.map(f)示例:
data={
    'fruit':['apple','orange','grape','banana'],
    'price':['25元','42元','35元','15元']
}
df=DataFrame(data)
df2=df1.copy()

def removeyuan(x):
    return x.split('元')[0]  # 取‘25元’中的‘25’

df['price']=df['price'].map(removeyuan)  # df['price'] 是序列
df1['price']=df1['price'].map(lambda x:x.split('元')[0]) 

# df.aplly(f,axis=1)示例:
df2=DataFrame(np.random.randn(3,3),columns=['a','b','c'],index=['linux','win','mac'])
f=lambda x:x.max()-x.min()  # 放在apply()里 x在这里代表 行或列
df2.apply(f)  

# df.applymap(f)示例: 
df2.applymap(lambda x:'%.2f'%x)  # 保留小数点两位


# 六, 数据排序  
# 排序不会影响原来的数据,返回新的数据。

# 1, Series数据排序
# 1-1) se.sort_index(ascending=False)   对 index进行排序 ascending缺省时默认升序,ascending=False为降序
s1=Series([1,-1,3,2],index=['b','a','d','c'])
s1.sort_index()                 # 升序
s1.sort_index(ascending=False)  # 降序
# 1-2) se.sort_values(ascending=False)  对 value进行排序  ascending缺省时默认升序,ascending=False为降序
s1.sort_values()
s1.sort_values(ascending=False)

# 2, DataFrame数据排序
# 2-1)df.sort_index(asix=1,ascending=False)   对指定轴数据的索引 进行排序  axis缺省时默认为 axis=0, ascending缺省时升序...
df1.sort_index(axis=0,ascending=True)        # 对行索引降序排序
# 2-2) df.sort_values(by='d',ascending=False)  对指定列的值进行排序  ascending缺省时默认升序
df1.sort_values(by='d',ascending=False) 


# 七, 汇总与统计  
# df.sum(axis=0)      axis=0 或 axis缺省 表示对【每一列】分别求和,axis=1表示对【每一行】求和,返回 Series数据。
# df.describe()      对每个数值型【列】进行统计,用于对数据的初步观察时使用,得到一个关于最值,平均值,标准差等信息的 DataFrame.

df=DataFrame(np.random.randn(3,3),columns=['a','d','c'])
df.sum()
df.sum(axis=1)
df.describe()


# 八, 唯一值与值计数 

# 1,series.unique()       获取序列(包括 DataFrame的行或列)不重复元素组成的 ndarray数组
s1=Series([2,-1,3,2,1,4,5,3,5])
s1.unique()  # array([ 2, -1,  3,  1,  4,  5], dtype=int64)
df1['fruit'].unique()
df1.iloc[2].unique()

# 2,series.value_counts() 统计序列中每个值出现的次数  返回以序列元素为索引,以次数为元素的 Series.
s1.value_counts()
df1['fruit'].value_counts()
df1.iloc[2].value_counts()


# 九, 层次化索引  
# 层次化索引就是轴上有多个级别索引,即索引是个多维列表 index=[[],[]],这里只讨论二维列表。

# 1, Series 数据的层次化索引创建:
series_obj=Series(np.random.randn(9),index=[['one','one','one','two','two','two','three','three','three'],['a','b','c']*3])
series_obj
# 对层次化序列的外层索引: series_obj['two']  
# 对层次化序列的内层索引: series_obj[:,'a']       # 所有行的 a 行
# 对层次化序列的内层索引: series_obj['two','a']   # two行的 a 行
eries_obj.index   # 该索引对象为 

# 2, DataFrame
# 对于 DataFrame,行和列都可以为层次化索引:
df1=DataFrame(np.arange(16).reshape(4,4),index=[['one','one','two','two'],['a','b','a','b']])
df2=DataFrame(np.arange(16).reshape(4,4),columns=[['one','one','two','two'],['a','b','a','b']])
df3=DataFrame(np.arange(16).reshape(4,4),index=[['one','one','two','two'],['a','b','a','b']],
              columns=[['apple','apple','orange','orange'],['size','price','size','price']])

df3['apple']
df3['apple','size']  # 返回从层次化索引序列
df3.loc['one']
df3.loc['one','a']  # 返回层次化索引序列

# 3, 重排分级顺序  df3.swaplevel(0,1) 用到再查

# 4, 对层次化索引的 pandas 数据进行汇总统计
# sum()的参数 level=0 表示按相同外层索引的所有子行或子列相加,level=1 表示按相同内层索引的行或列进行求和。
# 层次化索引的用途在后面会详细讲解。

df3.sum(level=0,axis=0)  # 表示按相同【外层】索引的所有子行或子列相加  one的 a+b  two的 a+b  
df3.sum(level=1,axis=0)  # 表示按相同【内层】索引的行或列进行求和     one的 a+a  two的 b+b  
df3.sum(level=0,axis=1)  # 表示按相同【外层】索引的所有子行或子列相加
df3.sum(level=1,axis=1)  # 表示按相同【内层】索引的行或列进行求和

原文地址:https://www.cnblogs.com/Collin-pxy/p/13038381.html