stack()和unstack()
pandas行转列, 列转行, 以及一行生成多行中, 我们主要要用到 stack() 和 unstack() 操作.
DataFrame.stack(self, level=- 1)
stack是将DataFram变为Series, DataFrame的列变成具有多级索引Series的最后一级索引, DataFrame的索引变成具有多级索引Series的其他索引.
DataFrame.unstack(self, level=- 1) / Series.unstack(self, level=- 1)
对于Series来说, unstack()是把最后一级索引变成对应DataFrame的列, 其他索引变成对应DataFrame的索引; 对于DataFrame来说, unstack()是将DataFram变为Series, DataFrame的列变成具有多级索引Series的一级索引, DataFrame的索引变成具有多级索引Series的其他索引.
例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| import pandas as pd
df0 = pd.DataFrame([[80, 85], [92, 90], [88, 78]], index=['小红', '小华', '小明'], columns=['数学', '语文']) '''df0: 数学 语文 小红 80 85 小华 92 90 小明 88 78 '''
se1 = df0.unstack(level=-1) '''se1: 数学 小红 80 小华 92 小明 88 语文 小红 85 小华 90 小明 78 dtype: int64 '''
df1 = se1.unstack(level=-1) '''df1 小红 小华 小明 数学 80 92 88 语文 85 90 78 '''
se2 = df0.stack(level=-1) '''se2: 小红 数学 80 语文 85 小华 数学 92 语文 90 小明 数学 88 语文 78 dtype: int64 '''
df2 = se2.unstack(level=-1) '''df2: 数学 语文 小红 80 85 小华 92 90 小明 88 78 '''
|
pivot()
DataFrame.pivot(self, index=None, columns=None, values=None)
用来调整DataFrame的索引, 列, 值.
例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| import pandas as pd
df = pd.DataFrame({ '姓名':['小红', '小红', '小华', '小华', '小明', '小明'], '科目':['数学', '语文', '数学', '语文', '数学', '语文'], '成绩':[88, 85, 92, 90, 88, 78] }) '''df: 姓名 科目 成绩 0 小红 数学 88 1 小红 语文 85 2 小华 数学 92 3 小华 语文 90 4 小明 数学 88 5 小明 语文 78 '''
df = df.pivot(index='姓名', columns) '''df: 科目 数学 语文 姓名 小华 92 90 小明 88 78 小红 88 85 '''
df = df.rename_axis(columns=None) '''df: 数学 语文 姓名 小华 92 90 小明 88 78 小红 88 85 '''
df = df.reset_index() '''df: 姓名 数学 语文 0 小华 92 90 1 小明 88 78 2 小红 88 85 '''
|
分割value问题
有这样一组数据:
姓名 |
年龄 |
爱好 |
小红 |
16 |
跳舞,唱歌,钢琴 |
小华 |
18 |
唱,跳,rap,篮球 |
小明 |
20 |
古筝,翻译 |
我们想要把它变成下面这样:
姓名 |
年龄 |
爱好 |
小红 |
16 |
跳舞 |
小红 |
16 |
唱歌 |
小红 |
16 |
钢琴 |
小华 |
18 |
唱 |
小华 |
18 |
跳 |
小华 |
18 |
rap |
小华 |
18 |
篮球 |
小明 |
20 |
古筝 |
小明 |
20 |
翻译 |
先导入数据:
1 2 3 4 5 6 7 8 9
| df = pd.DataFrame({ '姓名':['小红', '小华', '小明'], '年龄':[16, 18, 20], '爱好':['跳舞,唱歌,钢琴', '唱,跳,rap,篮球', '古筝,翻译'] }) '''df: 姓名 年龄 爱好 0 小红 16 跳舞,唱歌,钢琴 1 小华 18 唱,跳,rap,篮球 2 小明 20 古筝,翻译 '''
|
第一种方法
首先将df的姓名和年龄设置为索引(当前为列名):
1 2 3 4 5 6 7 8
| df = df.set_index(["姓名", "年龄"]) '''df: 爱好 姓名 年龄 小红 16 跳舞,唱歌,钢琴 小华 18 唱,跳,rap,篮球 小明 20 古筝,翻译 '''
|
此时df只有爱好这一列, 再将爱好这列分割:
1 2 3 4 5 6 7 8
| df = df["爱好"].str.split(",", expand=True) '''df: 0 1 2 3 姓名 年龄 小红 16 跳舞 唱歌 钢琴 None 小华 18 唱 跳 rap 篮球 小明 20 古筝 翻译 None None '''
|
此时字段已经被分割开来, 我们需要将这多列变为一列, 此时我们可以调用 stack(), 将列转变为Series的最后一级索引:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| se = df.stack() '''se: 姓名 年龄 小红 16 0 跳舞 1 唱歌 2 钢琴 小华 18 0 唱 1 跳 2 rap 3 篮球 小明 20 0 古筝 1 翻译 dtype: object '''
|
此时这个df已经转变为Series, 而此Series的最后一级索引一级没有了作用, 可以直接删掉:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| se = se.reset_index(drop=True, level=-1)
'''se: 姓名 年龄 小红 16 跳舞 16 唱歌 16 钢琴 小华 18 唱 18 跳 18 rap 18 篮球 小明 20 古筝 20 翻译 dtype: object '''
|
我们再调用一次reset_index(), 将Series的索引转变为DataFrame的列:
1 2 3 4 5 6 7 8 9 10 11 12 13
| df = se.reset_index() '''df: 姓名 年龄 0 0 小红 16 跳舞 1 小红 16 唱歌 2 小红 16 钢琴 3 小华 18 唱 4 小华 18 跳 5 小华 18 rap 6 小华 18 篮球 7 小明 20 古筝 8 小明 20 翻译 '''
|
最后再更改一下列名就完成了:
1 2 3 4 5 6 7 8 9 10 11 12 13
| df = df.rename(columns={0: "爱好"}) '''python 姓名 年龄 爱好 0 小红 16 跳舞 1 小红 16 唱歌 2 小红 16 钢琴 3 小华 18 唱 4 小华 18 跳 5 小华 18 rap 6 小华 18 篮球 7 小明 20 古筝 8 小明 20 翻译 '''
|
第二种方法
使用下面方法, 可以迅速使列表炸裂开.
DataFrame.explode(self, column)
首先我们将数据的”爱好”列转换为列表
1 2 3 4 5 6 7
| df["爱好"] = df["爱好"].str.split(",") '''df: 姓名 年龄 爱好 0 小红 16 [跳舞, 唱歌, 钢琴] 1 小华 18 [唱, 跳, rap, 篮球] 2 小明 20 [古筝, 翻译] '''
|
再使用该方法, 并指定”爱好”列, 就完成了:
1 2 3 4 5 6 7 8 9 10 11 12 13
| df = df.explode("爱好") '''df: 姓名 年龄 爱好 0 小红 16 跳舞 0 小红 16 唱歌 0 小红 16 钢琴 1 小华 18 唱 1 小华 18 跳 1 小华 18 rap 1 小华 18 篮球 2 小明 20 古筝 2 小明 20 翻译 '''
|
参考文献
[1] pandas行转列、列转行、以及一行生成多行 - 古明地盆 - 博客园