Pandas合并

ryluo 2020-06-14 01:29:22
Pandas系列

Datawhale组队学习pandas笔记

append与assign

append与assign都是向表中添加新的元素

append方法

Series添加

df_append = df.loc[:3, ['Address', 'Height']].copy()
df_append

s = pd.Series({'Address':'street_5', 'Height': 200}, name='new_data')
s

df_append.append(s)

DataFrame添加

s_f = pd.DataFrame({'Address':['street_5', 'street_20'], 'Height': [200, 300]}, index=['new_data1', 'new_data2'])
s_f

df_append.append(s_f)

assign方法

该方法主要用于添加列,列名直接由参数指定

s = pd.Series(list('abcd'), index=range(4))
s

df_append.assign(new_col=s)

同时添加多列

col1 = pd.Series(list('1234'), index=range(4))
col2 = pd.Series(list('abcd'), index=range(4))
df_append.assign(new_col1=col1, new_col2=col2)

combine与update

combine与update都是对表进行填充,可以根据某种规则进行填充

combine

DataFrame.combine(other, func, fill_value=None, overwrite=True)

基于传递的函数执行与另一个DataFrame的逐列组合。

使用func将DataFrame与其他 DataFrame 组合到按元素组合的列。生成的DataFrame的行索引和列索引将是两者的并集。

# 组合两个DataFrame的最小值
df1 = pd.DataFrame({'A': [0, 0], 'B': [4, 4]})
display(df1)
display(df2)
df2 = pd.DataFrame({'A': [1, 1], 'B': [3, 3]})
take_smaller = lambda s1, s2: s1 if s1.sum() < s2.sum() else s2
df1.combine(df2, take_smaller)

# df1.combine(df2, np.minimum)

在将列传递给合并函数之前,使用fill_value填充Nones

df1 = pd.DataFrame({'A': [0, 0], 'B': [None, 4]})
df2 = pd.DataFrame({'A': [1, 1], 'B': [3, 3]})
df1.combine(df2, np.minimum, fill_value=-5)

当数据维度不相同的时候,可以选择是否进行覆盖。默认是进行覆盖的

df1 = pd.DataFrame({'A': [0, 0], 'B': [4, 4]})
df2 = pd.DataFrame({'B': [3, 3], 'C': [-10, 1],}, index=[1, 2])
df1.combine(df2, take_smaller)
# 设置不进行覆盖
df1.combine(df2, take_smaller, overwrite=False)

combine_first方法

这个方法作用是用df2填补df1的缺失值,功能比较简单,但很多时候会比combine更常用

df1 = pd.DataFrame({'A': [None, 0], 'B': [None, 4]})
df2 = pd.DataFrame({'A': [1, 1], 'B': [3, 3]})
df1.combine_first(df2)
df1 = pd.DataFrame({'A': [None, 0], 'B': [4, None]})
df2 = pd.DataFrame({'B': [3, 3], 'C': [1, 1]}, index=[1, 2])
df1.combine_first(df2)

update

三个特点

  1. 返回的框索引只会与被调用框的一致(默认使用左连接,下一节会介绍)

  2. 第二个框中的nan元素不会起作用

  3. 没有返回值,直接在df上操作

# 索引完全对齐的情况
df1 = pd.DataFrame({'A': [1, 2, 3],
                    'B': [400, 500, 600]})
df2 = pd.DataFrame({'B': [4, 5, 6],
                    'C': [7, 8, 9]})
df1.update(df2)
df1
# 索引没有完全对齐,部分数据还是需要填充
df1 = pd.DataFrame({'A': ['a', 'b', 'c'],
                    'B': ['x', 'y', 'z']})
df2 = pd.DataFrame({'B': ['d', 'e']}, index=[1,2])
df1.update(df2)
df1
# 含有缺失值不会进行填充
df1 = pd.DataFrame({'A': [1, 2, 3],
                    'B': [400, 500, 600]})
df2 = pd.DataFrame({'B': [4, np.nan, 6]})
df1.update(df2)
df1

concat

df1 = pd.DataFrame({'A': ['A0', 'A1'],
                    'B': ['B0', 'B1']},
                    index = [0,1])
df2 = pd.DataFrame({'A': ['A2', 'A3'],
                    'B': ['B2', 'B3']},
                    index = [2,3])
df3 = pd.DataFrame({'A': ['A1', 'A3'],
                    'D': ['D1', 'D3'],
                    'E': ['E1', 'E3']},
                    index = [1,3])
display(df1)
display(df2)
display(df3)

默认拼接状态

pd.concat([df1,df2])

axis=1时沿列方向拼接

pd.concat([df1,df2],axis=1)
# 对于df1没有索引为2,3的元素,所以用NaN填充
# 同理df2没有索引为0,1的元素,所以用NaN填充

join设置为内连接(由于axis=0,因此列取交集)

pd.concat([df3,df1],join='inner')

join设置为外链接

pd.concat([df3,df1],join='outer',sort=True) #sort设置列排序,默认为False

也可以添加一个Series

s = pd.Series(['X0', 'X1'], name='X')
pd.concat([df1,s],axis=1)
## merge与join ### merge > merge函数的作用是将两个pandas对象横向合并,遇到重复的索引项时会使用**笛卡尔积**,默认inner连接,可选left、outer、right连接 > > 所谓左连接,就是指以第一个表索引为基准,右边的表中如果不再左边的则不加入,如果在左边的就以笛卡尔积的方式加入 > > merge/join与concat的不同之处在于on参数,可以指定某一个对象为key来进行连接 ```python left = pd.DataFrame({'key1': ['K0', 'K0', 'K1', 'K2'], 'key2': ['K0', 'K1', 'K0', 'K1'], 'A': ['A0', 'A1', 'A2', 'A3'], 'B': ['B0', 'B1', 'B2', 'B3']}) right = pd.DataFrame({'key1': ['K0', 'K1', 'K1', 'K2'], 'key2': ['K0', 'K0', 'K0', 'K0'], 'C': ['C0', 'C1', 'C2', 'C3'], 'D': ['D0', 'D1', 'D2', 'D3']}) right2 = pd.DataFrame({'key1': ['K0', 'K1', 'K1', 'K2'], 'key2': ['K0', 'K0', 'K0', 'K0'], 'C': ['C0', 'C1', 'C2', 'C3']}) display(left) display(right) display(right2) ```

以key1为准则连接,如果具有相同的列,则默认suffixes=(‘_x’,’_y’)

pd.merge(left, right, on='key1')

以多组键连接

pd.merge(left, right, on=['key1','key2'])

左连接

pd.merge(left, right, how='left', on=['key1', 'key2'])

右连接

pd.merge(left, right, how='right', on=['key1', 'key2'])

join

join函数作用是将多个pandas对象横向拼接,遇到重复的索引项时会使用笛卡尔积,默认左连接,可选inner、outer、right连接

left = pd.DataFrame({'A': ['A0', 'A1', 'A2'],
                     'B': ['B0', 'B1', 'B2']},
                    index=['K0', 'K1', 'K2'])
right = pd.DataFrame({'C': ['C0', 'C2', 'C3'],
                      'D': ['D0', 'D2', 'D3']},
                    index=['K0', 'K2', 'K3'])
left.join(right)

问题

  1. 请思考什么是append/assign/combine/update/concat/merge/join各自最适合使用的场景,并举出相应的例子
  2. merge_ordered和merge_asof的作用是什么?和merge是什么关系
  3. 请构造一个多级索引与多级索引合并的例子,尝试使用不同的合并函数
  4. 上文提到了连接的笛卡尔积,那么当连接方式变化时(inner/outer/left/right),这种笛卡尔积规则会相应变化吗?请构造相应例子。

问题与练习

练习一:

(a)

data1 = pd.read_csv('data/Employee1.csv')
data2 = pd.read_csv('data/Employee2.csv')
L = list(set(data1['Name']).intersection(set(data2['Name'])))
L

(b)

df_b1 = data1[~data1['Name'].isin(L)]
df_b2 = data2[~data2['Name'].isin(L)]
df_b = pd.concat([data1,data2]).set_index('Name')
df_b.head()