数据的连接

数据的连接是在数据处理和分析中常见的一个操作。当我们需要将多个数据集合并起来,以便

进行更全面、综合的分析时,就可以使用数据连接操作。

concat函数(连接)

concat函数是在pandas底下的方法,可以将数据根据不同的轴作简单的融合

提供行方向和列方向进行内联或外联的拼接操作

concat连接示例

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
df1 = pd.DataFrame({'A': ['A0', 'A1', 'A2', 'A3'],
'B': ['B0', 'B1', 'B2', 'B3'],
'C': ['C0', 'C1', 'C2', 'C3'],
'D': ['D0', 'D1', 'D2', 'D3']},
index=[0, 1, 2, 3])

df2 = pd.DataFrame({'A': ['A4', 'A5', 'A6', 'A7'],
'B': ['B4', 'B5', 'B6', 'B7'],
'C': ['C4', 'C5', 'C6', 'C7'],
'D': ['D4', 'D5', 'D6', 'D7']},
index=[4, 5, 6, 7])

# 参数axis默认是 0 行上拼接
result = pd.concat([df1, df2])
# 注意 此时和drop是一样的 axis = 1 是列拼接
result = pd.concat([df1, df2],axis = 1)

# 要在相接的时候在加上一个层次的key来识别数据源自于哪张表,可以增加key参数
result = pd.concat([df1, df2], keys=['x', 'y'])



df3 = pd.DataFrame({'B': ['B2', 'B3', 'B6', 'B7'],
'D': ['D2', 'D3', 'D6', 'D7'],
'F': ['F2', 'F3', 'F6', 'F7']} ,
index=[2, 3, 6, 7])


# 当axis = 1的时候,列拼接 ,然后将不同列名称的两张表合并
result = pd.concat([df1, df3], axis=1)

# 加上join参数的属性,如果为’inner’得到的是两表的交集,如果是outer,得到的是两表的并集。默认是 outer
result = pd.concat([df1, df3], axis=1, join='inner')

# ignore_index参数
pd.concat([df1,df3],ignore_index= True) # 和重置索引差不多
pd.concat([df1,df3]).reset_index(drop= True)

merge函数

提供类似于SQL数据库中的join连接功能,支持左联、右联、内联和外联等全部四种SQL连接操作类型

类似于关系型数据库的连接方式,可以根据一个或多个键将两张不同的DatFrame连接起来,由于默认how=‘inner’,故合并表仅保留key重名的行,不重名的行将被丢弃。( 备注: merge(),若有三个及以上表,需不断两两合并来实现
该函数的典型应用场景: 两张表有相同内容的某一列(类似SQL中的主键)也就是说两张表是有关系的,欲根据主键将两张表进行列拼接整合到一张表中

merge函数参数的理解

  • merge与concat的区别在于,merge需要依据某一共同列来进行合并
  • 使用pd.merge()合并时,会自动根据两者相同column名称的那一列,作为key来进行合并。
  • merge只能完成两张表的连接.concat是拼接,可以有多个表

how参数

可选值有{'left’, ‘right’, ‘outer’, ‘inner’}, 默认‘inner’。这四种连接方式分别类似于SQL中的{左联,右联,外联,内联}。 注意和concat的默认参数不一样

默认是how= ‘inner’

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
df1 = pd.DataFrame({'name':['Bobs','Linda','Bill'],
'group':['Accounting','Product','Marketing'],
'hire_date':[1998,2017,2018]})

df2 = pd.DataFrame({'name':['james','Bobs','Bill'],
'hire_dates':[1998,2016,2007]})



# 默认是inner连接
pd.merge(df1,df2)


# how = ' outer '
pd.merge(df1,df2,how= 'outer') # NaN值补全

pd.merge(df1,df2,how= 'left') # 以左表为基础,左表的所有都要,右表没有的 进行NaN值补充

一对一合并

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
df1 = pd.DataFrame({'employee':['Bob','Jake','Lisa'],
'group':['Accounting','Engineering','Engineering'],
})



df2 = pd.DataFrame({'employee':['Lisa','Bob','Jake'],
'hire_date':[2004,2008,2012],
})
df2

# 一对一合并
pd.merge(df1,df2,on='employee') # on如果不写,默认情况下使用两表中公有的列作为合并条件



df1 = pd.DataFrame({'employee':['Bob','Jake','Lisa'],
'group':[2004,3003,4004],
})

df2 = pd.DataFrame({'employee':['Lisa','Bob','Jake'],
'group':[2004,2008,2012],
})

pd.merge(df1,df2,on = 'group')

一对多合并

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

df3 = pd.DataFrame({
'employee':['Lisa','Jake'],
'group':['Accounting','Engineering'],
'hire_date':[2004,2016]})



df4 = pd.DataFrame({'group':['Accounting','Engineering','Engineering'],
'supervisor':['Carly','Guido','Steve']
})


pd.merge(df3,df4)


多对多合并

1
2
3
4
5
6
7
8
df1 = pd.DataFrame({'employee':['Bob','Jake','Lisa'],
'group':['Accounting','Engineering','Engineering']})

df5 = pd.DataFrame({'group':['Engineering','Engineering','HR'],
'supervisor':['Carly','Guido','Steve']
})

pd.merge(df1,df5,how='right') # 以右表为主
left_on参数

这是两张表都有一个相同的列名

那么如果没有相同的列名呢 ?(但是内容一样)

  • 当两张表没有可进行连接的列时,可使用left_on和right_on手动指定merge中左右两边的哪一列列作为连接的列
1
2
3
4
5
6
7
8
9
df1 = pd.DataFrame({'employee':['Bobs','Linda','Bill'],
'group':['Accounting','Product','Marketing'],
'hire_date':[1998,2017,2018]})

df5 = pd.DataFrame({'name':['Lisa','Bobs','Bill'],
'hire_dates':[1998,2016,2007]})


pd.merge(df1,df5,left_on='employee',right_on='name')
on参数

如果出现两个表中有两个及其两个以上的列名呢 ?

on为进行合并的参照列名,数据类型为字符串或字符串列表,该列名必须在两个表中都有才行并且是两个以上。如果什么都不写 ,方法会自动匹配两张表中相同的列名

1
2
3
4
5
6
7
8
9
10
11
df1 = pd.DataFrame({'name':['Bob','Lisa','Bill'],
'group':['Accounting','Product','Marketing'],
'hire_date':[1998,2004,2018]})

df2 = pd.DataFrame({'name':['Lisa','Bob','Jake'],
'hire_date':[2004,2008,2012],
})

pd.merge(df1,df2) # how默认inner join
pd.merge(df1,df2,on = 'name') # how默认inner join
pd.merge(df1,df2,on = 'hire_date') # how默认inner join

join函数

join函数参数的理解

该函数的典型应用场景:无重复列名的两个表df1和df2 基于行索引进行列拼接,直接使用df1.join(df2)即可,无需添加任何参数,合并表的行数与left表相同1,列数为left表+right表的列数之和,结果仅保留left表和right表中行索引相同的行,对列不做任何处理。如果两个表有重复的列名,需指定lsuffix, rsuffix参数。

参数的意义与merge方法基本相同,只是join方法默认为左外连接how=’left’

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#样集1
df1=pd.DataFrame(np.random.randint(1,100,size = (3,4)),columns=['A','B','C','D'])

#样集2
df2=pd.DataFrame({'b':[15,6],'d':[1,11],'a':[0,6]})

#默认是列拼接 ,注意写法
df1.join(df2)



#样集1
df1=pd.DataFrame(np.random.randint(1,100,size = (3,4))columns=['a','b','c','d'])

#样集2
df2=pd.DataFrame({'b':[15,6],'d':[1,11],'a':[0,6]})

#用join合并表df1和表df2,需指定lsuffix, rsuffix参数,标识两个表的重复列名
df1.join(df2, lsuffix='_l', rsuffix='_r')



append函数

提供行方向的拼接操作

1
2
3
4
5
df1 = pd.DataFrame(data=np.random.randint(0,100,size=(5,3)),columns=['A','B','C'])
df2 = pd.DataFrame(data=np.random.randint(0,100,size=(5,3)),columns=['A','D','C'])

df1.append(df2,ignore_index= True)

三者区别 :

map和apply

理解函数

1
2
3
4
5
6
7
8
9
10
11
12
def function():
pass

def my_sq(x):
return x**2


def avg_2(x,y):
return (x+y)/2

# 回顾一下 函数的使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
data = pd.read_csv('./map_nan_nv.csv')

# 有个要求 : 女变成0 男变成1 怎么做 ?

#如果需要把数据集中gender列的男替换为1,女替换为0,怎么做呢?绝对不是用for循环实现,使用Series.map()可以很容易做到,最少仅需一行代码。


#①使用字典进行映射
data["gender"] = data["gender"].map({"男":1, "女":0})


# pandas 如何使用函数的呢 ?
#②使用函数
def gender_map(x):
if x == "男" :
return 1
else :
return 0
#注意这里传入的是函数名,不带括号
data["gender"] = data["gender"].map(gender_map)


# 不论是利用字典还是函数进行映射,map方法都是把对应的数据逐个当作参数传入到字典或函数中,得到映射后的值。

映射操作

  • 概念:创建一个映射关系列表,把values元素和一个特定的标签或者字符串绑定(给一个元素值提供不同的表现形式)
  • 注意 : map是Series的方法,只能被Series调用

series的apply方法

同时Series对象还有apply方法,apply方法的作用原理和map方法类似,区别在于apply能够传入功能更为复杂的函数。怎么理解呢?一起看看下面的例子。

假设在数据统计的过程中,年龄age列有较大误差,需要对其进行调整(加上或减去一个值),由于这个加上或减去的值未知,故在定义函数时,需要加多一个参数bias,此时用map方法是操作不了的(传入map的函数只能接收一个参数),apply方法则可以解决这个问题。

1
2
3
4
5
6
7
8
def apply_age(x,bias):
return x+bias

data["age"] = data["age"].apply(apply_age,bias = 3 )

# 可以看到age列都加了3,当然,这里只是简单举了个例子,当需要进行复杂处理时,更能体现apply的作用。

# 总而言之,对于Series而言,map可以解决绝大多数的数据处理需求,但如果需要使用较为复杂的函数,则需要用到apply方法。

Dataframe的apply方法

Dataframe通常两个维度,因此当Dataframe应用一个函数的时候,首先需要指定该函数的轴是哪里,? 逐行还是逐列?

1
2
3
4
5
6
7
8
9
10
11
12
13
# 沿着0轴列进行求和
data[["height","weight","age"]].apply(np.sum, axis=0)


#那如果在实际使用中需要按行进行操作(axis=1),那整个过程又是怎么实现的呢?
def BMI(series):
print(series)
weight = series["weight"]
height = series["height"]
BMI = weight/height
return BMI

data["BMI"] = data.apply(BMI,axis=1) # 传进去的都是axis = 1 行数据