一、长宽表变形
-
pivot
将长表变换为宽表,输入有三个参数:
- index:变形后的行索引
- columns:需要转换到列索引的列
- values:列和行索引对应的值
例如,先生成一个表:
df = pd.DataFrame({'Class':[1,1,2,2], 'Name':['San Zhang','San Zhang','Si Li','Si Li'], 'Subject':['Chinese','Math','Chinese','Math'], 'Grade':[80,75,90,85]}) df Out[57]: Class Name Subject Grade 0 1 San Zhang Chinese 80 1 1 San Zhang Math 75 2 2 Si Li Chinese 90 3 2 Si Li Math 85
然后将姓名作为变换后的行索,subject转换为列索引:
df.pivot(index='Name',columns='Subject',values='Grade') Out[58]: Subject Chinese Math Name San Zhang 80 75 Si Li 90 85
注意点:
- columns和index对应的组合需满足唯一性,上面例子中,如果张三的数学改为语文,则会出错,因为(张三,语文)这个组合出现了两次。
- 输入的三个参数可以设为列表,返回多级索引。
-
pivot_table
为了解决povit中唯一性的限制,在povit的基础上多增加了参数:
- aggfunc:传入聚合函数
- margins:设为True可以统计边际值
回到第一节中的例子,张三和李四的考试有两次:
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 Out[61]: Name Subject Grade 0 San Zhang Chinese 80 1 San Zhang Chinese 90 2 San Zhang Math 100 3 San Zhang Math 90 4 Si Li Chinese 70 5 Si Li Chinese 80 6 Si Li Math 85 7 Si Li Math 95
使用pivot_table转换为宽表,aggfunc输入为两次相同科目的平均值,同时统计边界值:
df.pivot_table(index ='Name',columns='Subject',values='Grade',aggfunc='mean',margins=True) Out[64]: Subject Chinese Math All Name San Zhang 85 95.0 90.00 Si Li 75 90.0 82.50 All 80 92.5 86.25
-
melt
将宽表转换为长表,为pivot的逆运算。输入参数:
- id_vars:不需要被转换的列
- value_vars:需要被转换的列
- var_name:被转换列转换后的名字
- value_name:被转换列下的数据转换后的名字
例如,先生成一个表:
df = pd.DataFrame({'Class':[1,2], 'Name':['San Zhang', 'Si Li'], 'Chinese':[80, 90], 'Math':[80, 75]}) df Out[66]: Class Name Chinese Math 0 1 San Zhang 80 80 1 2 Si Li 90 75
然后使用melt函数将数学和语文合并成一个新的列:
df.melt(id_vars = ['Class','Name'], value_vars=['Chinese','Math'], var_name='Subject', value_name = 'Grade') Out[68]: Class Name Subject Grade 0 1 San Zhang Chinese 80 1 2 Si Li Chinese 90 2 1 San Zhang Math 80 3 2 Si Li Math 75
-
wide_to_long
将宽表变为长表,只不过相比于melt函数,其对应的信息可以表示多层含义:
- stubnames:被转换列下的数据转换后的名字
- i:不需要变换的列
- j:被转换列转换后的名字
例如,引入期中和期末信息,将数学和语文的期中和期末进行展示,先生成表:
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]}) ....: df Out[29]: Class Name Chinese_Mid Math_Mid Chinese_Final Math_Final 0 1 San Zhang 80 90 80 90 1 2 Si Li 75 85 75 85
进行转换:
pd.wide_to_long(df, ....: stubnames=['Chinese', 'Math'], ....: i = ['Class', 'Name'], ....: j='Examination', ....: sep='_', ....: suffix='.+') ....: Out[30]: Chinese Math Class Name Examination 1 San Zhang Mid 80 90 Final 80 90 2 Si Li Mid 75 85 Final 75 85
二、索引的变形
-
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 Out[41]: col_1 col_2 A cat big 1.0 1.0 dog small 1.0 1.0 B cat big 1.0 1.0 dog small 1.0 1.0
将内层(big和small)移动到列索引上:
df.unstack() Out[42]: col_1 col_2 big small big small A cat 1.0 NaN 1.0 NaN dog NaN 1.0 NaN 1.0 B cat 1.0 NaN 1.0 NaN dog NaN 1.0 NaN 1.0
移动多个层:
df.unstack([0,2]) Out[44]: col_1 col_2 A B A B big small big small big small big small cat 1.0 NaN 1.0 NaN 1.0 NaN 1.0 NaN dog NaN 1.0 NaN 1.0 NaN 1.0 NaN 1.0
注意点:
- 也具有唯一性,必须保证 被转为列索引的行索引层 和 被保留的行索引层 构成的组合是唯一的
-
stack
把列索引的层压入行索引中,用法和unstack类似。
三、其他变形函数
-
explode
对某一列的元素纵向展开,输入为要展开的列:
df_ex = pd.DataFrame({'A': [[1, 2], ....: 'my_str', ....: {1, 2}, ....: pd.Series([3, 4])], ....: 'B': 1}) ....: df_ex.explode('A') Out[61]: A B 0 1 1 0 2 1 1 my_str 1 2 {1, 2} 1 3 3 1 3 4 1
-
get_dummies
使用one-hot编码构建特征,例如:
s = pd.Series(list('abca')) pd.get_dummies(s) Out: a b c 0 1 0 0 1 0 1 0 2 0 0 1 3 1 0 0
四、练习
-
Ex1
a.思路:使用pivot函数将长表变为宽表,需要变换的列为
YYYY
:df_new = df.pivot(index=['COUNTY','State','SubstanceName'], columns='YYYY', values=['DrugReports'])
看了答案后发现还要reset_index:
df_new.reset_index.rename_axis(columns=:'YYYY':'')
b.思路:使用melt函数,然后还需要将nan值舍弃:
df_re = df_new.melt(id_vars=['COUNTY','State','SubstanceName'], value_vars=[2010,2011,2012,2013,2014,2015,2016,2017], var_name = 'YYYY', value_name = 'DrugReports').dropna(subset=['DrugReports'])
c. 使用pivot_table:
res1 = df.pivot_table(index='YYYY', columns='State', values='DrugReports', aggfunc='sum')
使用 groupby+unstack:
df_new = df.groupby(['State', 'YYYY'])['DrugReports'].sum() res2 = df_new.unstack(0)
-
Ex2
df = df.rename(columns={'Chinese':'new_Chinese', 'Math':'new_Math'}) pd.wide_to_long(df, stubnames=['new'], i = ['Class', 'Name'], j='Subject', sep='_', suffix='.+').reset_index().rename(columns={'new ':'Grade'})