df = pd.DataFrame({'Class':[2,2,1,1],
'Name':['San Zhang','San Zhang','Si Li','Si Li'],
'Subject':['Chinese','Math','Chinese','Math'],
'Grade':[80,75,90,85]})
df.loc[1,'Subject']='Chinese'
try:
df.pivot(index='Name',columns='Subject',values='Grade')
except Exception as e:
Err_Msg=e
df = pd.DataFrame({'Class':[1, 1, 2, 2, 1, 1, 2, 2],
'Name':['San Zhang', 'San Zhang', 'Si Li', 'Si Li',
'San Zhang', 'San Zhang', 'Si Li', 'Si Li'],
'Examination': ['Mid', 'Final', 'Mid', 'Final',
'Mid', 'Final', 'Mid', 'Final'],
'Subject':['Chinese', 'Chinese', 'Chinese', 'Chinese',
'Math', 'Math', 'Math', 'Math'],
'Grade':[80, 75, 85, 65, 90, 85, 92, 88],
'rank':[10, 15, 21, 15, 20, 7, 6, 2]})
pivot_multi= df.pivot(index = ['Class', 'Name'],
columns = ['Subject','Examination'],
values = ['Grade','rank'])
pivot的使用依赖于唯一性条件
不满足唯一性条件必须通过聚合操作使得相同行列组合对应的多个值变为一个值
df = pd.DataFrame({'Name':['San Zhang', 'San Zhang',
'San Zhang', 'San Zhang',
'Si Li', 'Si Li', 'Si Li', 'Si Li'],
'Subject':['Chinese', 'Chinese', 'Math', 'Math',
'Chinese', 'Chinese', 'Math', 'Math'],
'Grade':[80, 90, 100, 90, 70, 80, 85, 95]})
df.pivot_table(index='Name',columns='Subject',values='Grade',aggfunc='mean')
df.pivot_table(index='Name',columns='Subject',values='Grade',aggfunc=lambda x:x.mean())
在上面的边际汇总例子中,行或列的汇总为新表中行元素或者列元素的平均值,而总体的汇总为新表中四个元素的平均值。这种关系一定成立吗?若不成立,请给出一个例子来说明。
#假设Lisi 多加一项数学的成绩
df =pd.DataFrame({'Name':['San Zhang', 'San Zhang',
'San Zhang', 'San Zhang',
'Si Li', 'Si Li', 'Si Li', 'Si Li','Si Li'],
'Subject':['Chinese', 'Chinese', 'Math', 'Math',
'Chinese', 'Chinese', 'Math', 'Math','Math'],
'Grade':[80, 90, 100, 90, 70, 80, 85, 95,91]})
df.pivot_table(index='Name',columns='Subject',values='Grade',aggfunc='mean', margins=True)
可以看到lisi的数学平均分:(85+95+91)/3=90.3333
(85+95)/2=90
这导致了总均分统计的时候All=(95+91+85+70+80)/5=84.2
id_vars:列变量
在下面的例子中,Subject
以列索引的形式存储,现在想要将其压缩到一个列中。
需要从列压缩到行的变量:value_vars:[] -> 名字var_name
原来列变量值的含义:value_name:列变量值的名字
df=pd.DataFrame({'Class':[1,2],'Name':['San Zhang','Si Li'],
'Chinese':[80,90],'Math':[80,75]})
df_melted=df.melt(id_vars=['Class','Name'],value_vars=['Chinese','Math'],var_name='Subject',value_name='Grade')
#通过pivot转回df
df_unmelted=df_melted.pivot(index=['Class','Name'],columns='Subject',values='Grade')
#多了一个Subject,需要恢复索引
df_unmelted=df_unmelted.reset_index().rename_axis({'Subject':''})
列中包含了交叉类别,比如math_mid,math_final这样的列
df=pd.DataFrame({'Class':[1,2],'Name':['San Zhang','Si Li'],
'Chinese_Mid':[80,75],'Math_Mid':[90,85],
'Chinese_Final':[80,75],'Math_Final':[90,85]
})
pd.wide_to_long(df,stubnames=['Chinese','Nath'],i=['Class','Name'],j='Examination',sep='_',suffix='.+')
res=pivot_multi.copy()#
res.columns=res.columns.map(lambda x:'_'.join(x))
res=res.reset_index()#重置索引
res=pd.wide_to_long(res,stubnames=['Grade','rank'],i=['Class','Name'],
j='Subject_Examination',sep='_',suffix='.+')
res=res.reset_index()
res[['Subject','Examination']]=res['Subject_Examination'].str.split("_",expand=True)
res=res[['Class','Name','Examination', 'Subject', 'Grade', 'rank']].sort_values('Subject')
#sort_values根据某个字段进行排序
res=res.reset_index(drop=True)
_
进行分割,expand=True可以扩展res.columns=res.columns.map(lambda x:'_'.join(x))
利用swaplevel或者reorder_levels进行索引内部的层交换
属于某一列或几列
元素
\color{red}{元素}
元素和
列索引
\color{red}{列索引}
列索引之间的转换,而不是索引之间的转换
unstack 将行索引转换为列索引
df=pd.DataFrame(np.ones((4,2)),
index = pd.Index([('A', 'cat', 'big'),
('A', 'dog', 'small'),
('B', 'cat', 'big'),
('B', 'dog', 'small')]),
columns=['col_1', 'col_2'])
df.unstack()
等同于
df.unstack(2)
#同时转化多层
df.unstack([0,2])
#唯一性证明
my_index=df.index.to_list()
my_index[1]=my_index[0]
df.index=pd.Index(my_index)#构造index
try:
df.unstack()
except Exception as e:
Err_Msg=e
Err_Msg
stack 将列索引层压入行索引
df = pd.DataFrame(np.ones((4,2)),
index = pd.Index([('A', 'cat', 'big'),
('A', 'dog', 'small'),
('B', 'cat', 'big'),
('B', 'dog', 'small')]),
columns=['index_1', 'index_2']).T
df
df.stack()
df.stack([1,2])
在上面介绍的所有函数中,除了带有聚合效果的pivot_table
以外,所有的函数在变形前后并不会带来values
个数的改变,只是这些值在呈现的形式上发生了变化。在上一章讨论的分组聚合操作,由于生成了新的行列索引,因此必然也属于某种特殊的变形操作,但由于聚合之后把原来的多个值变为了一个值,因此values
的个数产生了变化,这也是分组聚合与变形函数的最大区别。
变形:呈现形式发生了变化
分组聚合:将原来多个值变成了一个值
pivot_table能完成crosstab的所有功能
cross能统计元素组合出现的频数.(count操作)
统计learn_pandas
数据集中学校和转系情况对应的频数:
df=pd.read_csv('../data/learn_pandas.csv')
pd.crosstab(index=df.School,columns=df.Transfer)
#等价于
pd.crosstab(index=df.School,columns=df.Transfer,values=[0]*df.shape[0],aggfunc='count')
#等价于
df.pivot_table(index='School',columns='Transfer',values='Name',aggfuc='count')
两个函数的区别:
pivot_table传入的是被调用表对应的名字
crosstab的对应位置传入的是具体的序列
explode参数能够对某一列的元素进行纵向的展开
被展开的单元格必须存储 中的一种类型
list
tuple
Series
np.ndarray
df_ex=pd.DataFrame({'A':[[1,2],'my_str',{1,2},pd.Series([3,4])]})
df_ex.explode('A')
#此时对应的行号不会变
get_dummies
是用于特征构建的重要函数之一,其作用是把类别特征转为指示变量。
pd.get_dummies(df.Grade).head()
现有一份关于美国非法药物的数据集,其中SubstanceName, DrugReports
分别指药物名称和报告数量:
df = pd.read_csv('../data/drugs.csv').sort_values(['State','COUNTY','SubstanceName'],ignore_index=True)
df.head(3)
df_1=df.pivot(index=['State','COUNTY','SubstanceName'],columns="YYYY",values='DrugReports')
df_1.reset_index().rename_axis(columns={'YYYY':''})
df_2=df_1.melt(id_vars=['State','COUNTY','SubstanceName'],
value_vars=df_1.columns[3:],
var_name='YYYY',value_name='DrugReports').dropna(subset=['DrugReports']).astype({'YYYY':'int64','DrugReports':'int64'})
df_2=df_2.sort_values(['State','COUNTY','SubstanceName'],ignore_index=True).reindex_like(df)
df_2.equals(df)
State
分别统计每年的报告数量总和,其中State, YYYY
分别为列索引和行索引,要求分别使用pivot_table
函数与groupby+unstack
两种不同的策略实现,并体会它们之间的联系。df_3=df_2.pivot_table(index='YYYY',columns='State',values='DrugReports',aggfunc='sum')
df_3.head()
df_4=df.groupby(['State','YYYY'])['DrugReports'].sum().to_frame()
df_4.head()
df_5=df_4.unstack(0).droplevel(0,axis=1)
从功能上看,melt
方法应当属于wide_to_long
的一种特殊情况,即stubnames
只有一类。请使用wide_to_long
生成melt
一节中的df_melted
。(提示:对列名增加适当的前缀)
df = pd.DataFrame({'Class':[1,2],
'Name':['San Zhang', 'Si Li'],
'Chinese':[80, 90],
'Math':[80, 75]})
df1=df.rename(columns={'Chinese':'pre_Chinese','Math':'pre_Math'})
pd.wide_to_long(df1,stubnames=['pre'],
i=['Class','Name']
j='subject',sep='_',suffix='.+').reset_index().rename(columns={'pre':'Grade'})