文章主要实现的是使用map对传入的序列中每个元素进行计算,使用reduce对传入的序列中第一个元素进行计算后得到计算结果、再将这个结果对下一个元素进行计算,直至结束。在使用Python数据清洗时,这两个函数可以有效减少代码冗余、提升计算效率等。
本篇文章既然讲Python数据清洗常用的map和reduce函数,那么首先说明下两个函数的不同点,以便有几个简单的印象。
参数不同
- map接收两个参数,第一个参数是函数,第二个参数是序列(列表),函数可以接收一个或多个参数。
- reduce接收两个参数,第一个参数是函数,第二个参数是序列(列表),但函数只能接收两个参数。
计算逻辑不同
map()是将传入的函数依次作用到序列的每个元素,每个元素都是独自被函数计算一次;
reduce()是将传人的函数作用在序列的第一个元素并得到结果后,把这个结果继续与下一个元素作用,直到序列结束;
下面将通过实际的案例进行说明。
map函数的应用场景
map函数接收两个输入参数,第一个参数是函数(仅接受一个参数)、第二个参数是Iterable,由于Iterator是惰性序列( 惰性是指你不主动去遍历计算它,就不会计算其中元素的值),因此通过list()函数让它把整个序列都计算出来并返回一个list。
map函数将传入的函数依次计算到传入序列的每个元素,并把结果作为新的Iterator返回。
map函数在Python数据清洗时迭代计算的对象是列表(也就是说只要数据放到列表中就行,理论上列表里也可以是字典、df、series等等),主要的应用场景包括:
- 列表的数学运算
- 列表的格式转换
- 列表的字符串分割
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等等),主要的应用场景包括:
- 多个数据框join
- 列表的递推计算
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)
|