python数据清洗之map和reduce函数的使用方法

文章主要实现的是使用map对传入的序列中每个元素进行计算,使用reduce对传入的序列中第一个元素进行计算后得到计算结果、再将这个结果对下一个元素进行计算,直至结束。在使用Python数据清洗时,这两个函数可以有效减少代码冗余、提升计算效率等。



本篇文章既然讲Python数据清洗常用的map和reduce函数,那么首先说明下两个函数的不同点,以便有几个简单的印象。

参数不同

  1. map接收两个参数,第一个参数是函数,第二个参数是序列(列表),函数可以接收一个或多个参数。
  2. reduce接收两个参数,第一个参数是函数,第二个参数是序列(列表),但函数只能接收两个参数。

计算逻辑不同

map()是将传入的函数依次作用到序列的每个元素,每个元素都是独自被函数计算一次;

reduce()是将传人的函数作用在序列的第一个元素并得到结果后,把这个结果继续与下一个元素作用,直到序列结束;

下面将通过实际的案例进行说明。


map函数的应用场景

map函数接收两个输入参数,第一个参数是函数(仅接受一个参数)、第二个参数是Iterable,由于Iterator是惰性序列( 惰性是指你不主动去遍历计算它,就不会计算其中元素的值),因此通过list()函数让它把整个序列都计算出来并返回一个list。

map函数将传入的函数依次计算到传入序列的每个元素,并把结果作为新的Iterator返回。

map函数在Python数据清洗时迭代计算的对象是列表(也就是说只要数据放到列表中就行,理论上列表里也可以是字典、df、series等等),主要的应用场景包括:

  1. 列表的数学运算
  2. 列表的格式转换
  3. 列表的字符串分割

map函数应用案例

1
2
3
4
5
6
%%timeit
def function_map(x):
return x * x
r = list(map(function_map, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]))

996 ns ± 25.5 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

上边是对list=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]中的每个元素执行了2次方的计算,代码执行时长约996纳秒。

同时,map的计算过程也可以通过for循环的方式计算,但循环的计算效率将极大地下降,如下:

1
2
3
4
5
6
7
%%timeit
items = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
squared = []
for i in items:
squared.append(i**2)

3.12 µs ± 162 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

上边同样是对list=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]中的每个元素执行了2次方的计算,代码执行时长约3.12微秒,1微妙=1000纳秒,也就是说map的计算时间比for循环的计算时间缩短了3倍,map完胜。

1
2
3
4
5
6
7
8
9
%%timeit
def function_map(x, y, z):
return x + y + z
x1 = [1, 2, 3, 4, 5]
x2 = [1, 1, 6, 2, 3]
x3 = [1, 2, 3, 4, 5]
s = map(function_map, zip(x1, x2, x3))

429 ns ± 12.3 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

从计算过程看得出来map作为高阶函数、它事实上把运算规则抽象了、那么也就可以在现实工作中进行复杂的逻辑计算。



reduce函数的应用内场景

reduce函数同样是接收两个输入参数,第一个参数是函数(仅接受两个参数)、第二个参数是Iterable,细心的朋友们可能会发现这两个函数有一个不同点,那就是第一个参数函数接受的输入参数个数不同,map函数第一个参数是函数只能接受一个参数的输入,而reduce函数第一个参数是函数可以接受两个参数的输入,这在不同程度解决掉了很大计算开销的问题。

reduce函数在迭代序列的过程中,首先把列表中 前两个元素(只能两个)传给 函数,函数加工后,然后把 得到的结果和第三个元素 作为两个参数传给函数参数, 依次类推直至结束。

reduce函数在Python数据清洗时迭代计算的对象是列表(也就是说只要数据放到列表中就行,理论上列表里也可以是字典、df、series等等),主要的应用场景包括:

  1. 多个数据框join
  2. 列表的递推计算

reduce函数应用案例-多个数据框join

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def function_reduce(x, y):
return pd.merge(x, y, how='left', on=['id'])


t1 = pd.DataFrame({'id': [1, 2, 3, 4, 5], 'name': ['张一', '张二', '张三', '张四', '张五']})
t2 = pd.DataFrame({'id': [1, 2, 3, 4, 5], 'city': ['上海', '北京', '成都', '重庆', '深圳']})
t3 = pd.DataFrame({'id': [1, 2, 3, 4, 5], 'occupation': ['分析师', '工程师', '销售', 'HR', '前台']})

tf = reduce(function_reduce, [t1, t2, t3])

out:
id name city occupation
0 1 张一 上海 分析师
1 2 张二 北京 工程师
2 3 张三 成都 销售
3 4 张四 重庆 HR
4 5 张五 深圳 前台

reduce函数应用案例-多个数据集中的并集和交集

1
2
3
4
5
6
7
8
9
10
11
12
13
14
%%timeit
def function_reduce(x, y):
return x & y
sets = [{1, 2, 3, 4, 5}, {1, 5}, {2, 5, 1}]
s = reduce(function_reduce, sets)
640 ns ± 29 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)


%%timeit
def function_reduce(x, y):
return x | y
sets = [{1, 2, 3, 4, 5}, {1, 5}, {2, 5, 1}]
s = reduce(function_reduce, sets)
751 ns ± 31.6 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

reduce函数应用案例-转换格式并累积计算

1
2
3
4
5
6
%%timeit
def function_reduce(x, y):
return int(x) + int(y)
ls1 = [str(i) for i in range(10)]
sum = reduce(function_reduce, ls1)
3.62 µs ± 285 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)