pandas拆分及组合矩阵

一列拆分为多行

如下代码所示,该数据框中最后两列的部分数据为逗号分隔开的多个值。目前希望将数据框中的数据分割成为单条数据一行的格式。

1
2
3
4
   name  color       size
1 AAAA pink,yellow 18M,14S
2 BBBB black,blue 10S,12L
3 CCCC red 13M

想要得到的数据框格式如下:

1
2
3
4
5
6
7
8
9
10
   name  color  size
0 AAAA pink 18M
1 AAAA pink 14S
2 AAAA yellow 18M
3 AAAA yellow 14S
4 BBBB black 10S
5 BBBB black 12L
6 BBBB blue 10S
7 BBBB blue 12L
8 CCCC red 13M

实现思路:对于color和size列按照逗号对各个值进行拆分,将单个值转化为一行,同时相应的name列增加相应行。

在其中数据的拆分在pandas里有stack()函数可以完成该功能。该函数的完整文档和范例代码可见这里

由于矩阵经过拆分后行数增多,其索引也会发生变化,需要使用reset_index()函数对新数据框的索引进行重设。reset_index()的相关文档可见这里

以下为实现代码:

1
2
3
4
5
6
7
8
import pandas as pd
s = ['color','size']
df1= df.drop(columns = s, axis =1)

for x in s:
df1 = df1.join(df[x].str.split(',',expand = True).stack().reset_index(level=1,drop=True).rename(x))

df1 = df1.reset_index(drop = True)

lambda结合apply对数据框的特定元素进行处理

lambda是python中的匿名函数,即没有具体名称的函数。它允许快速定义单行函数,可以用在任何需要函数的地方。因此,这类函数一般用于定义少次使用且功能较简单的功能(因为lambda表达式后只可以跟一个表达式,限制了函数的复杂性)。
其语法为:lambda 参数:操作(参数)

关于lambda使用可以参考以下例子:

1
map( lambda x: x^2, [y for y in range(10)] )

以上的例子表示对于一个序列中的所有元素都平方。其中这里的map()可以将lambda所定义的表达式映射到list中的每个元素。同理,可以考虑将lambda所定义的表达式应用于数据框的某列元素或所有元素。
在pandas中,实现此功能的函数为apply
该函数的语法为:

1
DataFrame.apply(func, axis=0, broadcast=None, raw=False, reduce=None, result_type=None, args=(), **kwds)[source]

其中,func 表示要执行的函数,axis表示数据传入方式,axis=0表示逐行传入数据,而axis=1表示逐列传入数据。
最终,所有结果会以series数据结构返回。以上面的数据框为例,以下为将name等于AAAA的替换为全小写字符’’:

1
df['name'] = df4['name'].apply(lambda x: lower(x) if x=='AAAA' else x)

数据框的拼接方法

pandas中提供的数据框拼接方法有:concat, append, join及merge四种,它们的特点和区别可见下表:

方法 特性
concat 可以使数据框间行方向或列方向进行外联或内联拼接
append 数据框行方向拼接
join 数据框列方向拼接,支持左联、右联、内联和外联四种操作
merge 类似SQL数据库的联表操作,支持左、右、内、外联四种操作

pd.concat()

1
2
3
4
5
6
7
8
9
10
11
concat(objs, axis=0, join='outer', join_axes=None, ignore_index=False,
keys=None, levels=None, names=None, verify_integrity=False,
copy=True)
"""
常用参数说明:
axis:拼接轴方向,默认为0,行方向拼接;若为1,列方向拼接
join:默认外联'outer',拼接另一轴所有的label,缺失值用NaN填充;内联'inner',只拼接另一轴相同的label;
join_axes: 指定需要拼接的轴的labels,可在join既不内联又不外联的时候使用
ignore_index:对index进行重新排序
keys:多重索引
"""

部分用法示例:

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
>>> df1
a b c
1 a1 b1 c1
2 a2 b2 c2
3 a3 b3 c3

>>> df2
c d e
3 c3 d3 e3
4 c4 d4 e4
5 c5 d5 e5

>>> pd.concat([df1,df2]) # 默认沿axis=0,join=‘out’的方式进行concat
a b c d e
1 a1 b1 c1 NaN NaN
2 a2 b2 c2 NaN NaN
3 a3 b3 c3 NaN NaN
3 NaN NaN c3 d3 e3
4 NaN NaN c4 d4 e4
5 NaN NaN c5 d5 e5

>>> pd.concat([df1,df2], axis=1, join='inner') # 沿列进行合并,采用外联方式因为行中只有index=3是重复的,所以只有一行
a b c c d e
3 a3 b3 c3 c3 d3 e3

>>> pd.concat([df1,df2], axis=1, join_axes=[df1.index]) # 指定只取df1的index
a b c c d e
1 a1 b1 c1 NaN NaN NaN
2 a2 b2 c2 NaN NaN NaN
3 a3 b3 c3 c3 d3 e3

df.append()

1
2
3
4
5
6
7
append(self, other, ignore_index=False, verify_integrity=False)
"""
常用参数说明:
other:另一个df
ignore_index:若为True,则对index进行重排
verify_integrity:对index的唯一性进行验证,若有重复,报错。若已设置ignore_index,则该参数无效
"""

部分用法示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 以上面的df1和df2为例,使用append方法
>>> df1.append(df2) # 效果类似于pd.concat([df1,df2])
a b c d e
1 a1 b1 c1 NaN NaN
2 a2 b2 c2 NaN NaN
3 a3 b3 c3 NaN NaN
3 NaN NaN c3 d3 e3
4 NaN NaN c4 d4 e4
5 NaN NaN c5 d5 e5

>>> df1.append(df2, ignore_index=True) #对index进行重排,效果类似于pd.concat([df1,df2], ignore_index=True)
a b c d e
0 a1 b1 c1 NaN NaN
1 a2 b2 c2 NaN NaN
2 a3 b3 c3 NaN NaN
3 NaN NaN c3 d3 e3
4 NaN NaN c4 d4 e4
5 NaN NaN c5 d5 e5

df.join()

1
2
3
4
5
6
7
8
9
join(other, on=None, how='left', lsuffix='', rsuffix='', sort=False)
"""
常用参数说明:
on:参照的左边df列名key(可能需要先进行set_index操作),若未指明,按照index进行join
how:{‘left’, ‘right’, ‘outer’, ‘inner’}, 默认‘left’,即按照左边df的index(若声明了on,则按照对应的列);若为‘right’abs照左边的df
若‘inner’为内联方式;若为‘outer’为全连联方式。
sort:是否按照join的key对应的值大小进行排序,默认False
lsuffix,rsuffix:当left和right两个df的列名出现冲突时候,通过设定后缀的方式避免错误
"""

部分用法示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
>>> df3
name value
0 nike 3
1 vivian 4
2 mike 2
3 ben 5

>>> df4
name value
0 nike 8
1 vivian 2
2 mike 3
3 ben 4

>>> df3.join(df4) # 由于两者有相同的列名‘value’,所以不能合并,程序报错
>>> df3.join(df4, lsuffix='df3', rsuffix='df4')
name value_df3 value_df4
0 nike 3 8
1 vivian 4 2
2 mike 2 3
3 ben 5 4

df.merge()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
pd.merge(left, right, how='inner', on=None, left_on=None, right_on=None,
left_index=False, right_index=False, sort=False,
suffixes=('_x', '_y'), copy=True, indicator=False,
validate=None):
"""
常用参数说明:
how:{'left’, ‘right’, ‘outer’, ‘inner’}, 默认‘inner’,类似于SQL的内联。'left’类似于SQL的左联;'right’类似于SQL的右联;
‘outer’类似于SQL的全联。
on:进行合并的参照列名,必须一样。若为None,方法会自动匹配两张表中相同的列名
left_on: 左边df进行连接的列
right_on: 右边df进行连接的列
suffixes: 左、右列名称前缀
validate:默认None,可定义为“one_to_one” 、“one_to_many” 、“many_to_one”和“many_to_many”,即验证是否一对一、一对多、多对一或多对多关系
"""

部分用法示例:

1
2
3
4
5
6
7
8
9
10
# 使用上述df1及df2作为数据框例子
>>> pd.merge(df1, df2) #on为None,自动找寻相同的列名,且默认为内联,返回交集数据
 a b c d e
0 a3 b3 c3 d3 e3

>>> pd.merge(df1, df2, left_on='a',right_on='d', how='left') #以左边的df1为标准进行连接
a b c_x c_y d e
0 a1 b1 c1 NaN NaN NaN
1 a2 b2 c2 NaN NaN NaN
2 a3 b3 c3 NaN NaN NaN

参考资料:

1.python – pandas:如何将一列中的文本拆分为多行?
2.Pandas中的拼接操作(concat,append,join,merge)