20201226更新:df.join连接后,保证左连接的df的index不被排序
caller.join(other.set_index('uid'), on='uid')
#DataFrame的join连接时,caller的关键列 默认为index(可以使用参数on指定别的列为关键列);
#但是other的关键列永远都是index,所有使用别的列为关键列时,常常使用set_index()
df2 = pd.read_clipboard()
df = df1.join(df2.set_index('uid'),on='uid')
df = df.fillna('0')
df['share_uv'] = df['share_uv'].astype('int')
df.to_excel('D:/2020.xlsx')
20200917更新
【pivot_table解决pivot的重复问题】
The pivot_table method comes to solve this problem.
It works like pivot, but it aggregates the values from rows with duplicate entries for the specified columns.
【stack后变高,unstack后变宽】
Reshaping in Pandas - Pivot, Pivot-Table, Stack, and Unstack explained with Pictures
python基础再复习
【Python内建了map()、reduce()、filter()、sorted()函数】
- map()函数接收两个参数,一个是函数,一个是Iterable,map将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回。
- reduce()把一个函数作用在一个序列[x1, x2, x3, ...]上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算,其效果就是:reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
- filter()也接收一个函数和一个序列。和map()不同的是,filter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素。返回的是一个Iterator,也就是一个惰性序列,所以要强迫filter()完成计算结果,需要用list()函数获得所有结果并返回list。
- sorted()函数也是一个高阶函数,它还可以接收一个key函数来实现自定义的排序,例如按绝对值大小排序。key指定的函数将作用于list的每一个元素上,并根据key函数返回的结果进行排序。
from functools import reduce
【可迭代对象(可以直接作用于for循环的对象):Iterable】VS【迭代器(被next()函数调用并不断返回下一个值的对象,表示一个惰性计算的序列):Iterator】生成器都是Iterator对象,但list、dict、str虽然是Iterable,却不是Iterator。把list、dict、str等Iterable变成Iterator可以使用iter()函数:
所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。
Iterator甚至可以表示一个无限大的数据流,例如全体自然数。
而使用list是永远不可能存储全体自然数的。
【生成器:一边循环一边计算的机制,称为生成器:generator(列表生成式的[]改成(),就创建了一个generator;generator保存的是算法)】通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。
定义generator的另一种方法。如果一个函数定义中包含yield关键字,
那么这个函数就不再是一个普通函数,而是一个generator
而变成generator的函数,在每次调用next()的时候执行,
遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。
【在一个列表生成式中,for前面的if ... else是表达式,而for后面的if是过滤条件,不能带else】
把if写在for前面必须加else,否则报错
[x if x % 2 == 0 else -x for x in range(1, 11)]
跟在for后面的if是一个筛选条件,不能带else
[x for x in range(1,11) if x%2==0]
【列表生成式:使用两层循环,可以生成全排列】
[m + n for m in 'ABC' for n in 'XYZ']
【如何判断一个对象是可迭代对象呢?方法是通过collections??榈腎terable类型判断】Python内置的enumerate函数可以把一个list变成索引-元素对,这样就可以在for循环中同时迭代索引和元素本身
>>> from collections import Iterable
>>> isinstance('abc', Iterable)
# str是否可迭代
【必选参数、默认参数(必须指向不变对象)、可变参数(numbers,表示传入0个或任意个参数,这些可变参数在函数调用时自动组装为一个tuple)、命名关键字参数(定义命名的关键字参数在没有可变参数的情况下不要忘了写分隔符,否则定义的将是位置参数)和关键字参数(传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict)】
默认参数有个最大的坑(定义默认参数要牢记一点):默认参数必须指向不变对象!Python函数在定义的时候,默认参数L的值就被计算出来了,即[],因为默认参数L也是一个变量,它指向对象[],每次调用该函数,如果改变了L的内容,则下次调用时,默认参数的内容就变了,不再是函数定义时的[]了。
【默认参数(必须指向不变对象)】
def add_end(L=None):
if L is None:
L = []
L.append('END')
return L
def add_end(L=[]):
L.append('END')
return L
【可变参数(*numbers,表示传入0个或任意个参数,这些可变参数在函数调用时自动组装为一个tuple)】
如果已经有一个list或者tuple,要调用一个可变参数怎么办?可以这样做:
>>> nums = [1, 2, 3]
>>> calc(nums[0], nums[1], nums[2])
14
这种写法当然是可行的,问题是太繁琐,所以Python允许你在list或tuple前面加一个*号,把list或tuple的元素变成可变参数传进去:
>>> nums = [1, 2, 3]
>>> calc(*nums)
14
*nums表示把nums这个list的所有元素作为可变参数传进去。这种写法相当有用,而且很常见。
【关键字参数(传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict)】
传入任意个数的关键字参数:
>>> person('Bob', 35, city='Beijing')
name: Bob age: 35 other: {'city': 'Beijing'}
>>> person('Adam', 45, gender='M', job='Engineer')
name: Adam age: 45 other: {'gender': 'M', 'job': 'Engineer'}
【函数可以返回多个值吗?答案是肯定的;函数可以同时返回多个值,但其实就是一个tuple】
函数定义:如果有必要,可以先对参数的数据类型做检查;
Python函数返回的仍然是单一值。返回值是一个tuple!但是,在语法上,返回一个tuple可以省略括号,而多个变量可以同时接收一个tuple,按位置赋给对应的值,所以,Python的函数返回多值其实就是返回一个tuple,但写起来更方便。
【import】如果你已经把abs()的函数定义保存为abstest.py文件了,那么,可以在该文件的当前目录下启动Python解释器,用from abstest import my_abs来导入my_abs()函数,注意abstest是文件名(不含.py扩展名)
┌────────────────────────────────────────────────────────┐
│Command Prompt - python - □ x │
├────────────────────────────────────────────────────────┤
│>>> from abstest import my_abs │
│>>> my_abs(-9) │
│9 │
│>>> _ │
│
【list和dict的优缺点】
- 和list比较,dict(dict是空间换时间:查找快,但内存大)有以下几个特点:
查找和插入的速度极快,不会随着key的增加而变慢;
需要占用大量的内存,内存浪费多。
dict的key必须是不可变(如字符串、整数,而list是可变的,就不能作为key)对象。这个通过key计算位置的算法称为哈希算法(Hash)。要保证hash的正确性,作为key的对象就不能变。 - 而list(list是时间换空间:查找慢,但内存小)相反:
查找和插入的时间随着元素的增加而增加;
占用空间小,浪费内存很少。
【循环】
break语句可以在循环过程中直接退出循环,而continue语句可以提前结束本轮循环,并直接开始下一轮循环。break和continue这两个语句通常都必须配合if语句使用。
【不变对象】
为什么要设计str、None这样的不变对象呢?因为不变对象一旦创建,对象内部的数据就不能修改,这样就减少了由于修改数据导致的错误。此外,由于对象不变,多任务环境下同时读取对象不需要加锁,同时读一点问题都没有。我们在编写程序时,如果可以设计一个不变对象,那就尽量设计成不变对象。
【tuple的 指向不变 VS 内容不变】tuple所谓的“不变”是说,tuple的每个元素,指向永远不变。即指向'a',就不能改成指向'b',指向一个list,就不能改成指向其他对象,但指向的这个list本身是可变的!
>>> t = ('a', 'b', ['A', 'B'])
>>> t[2][0] = 'X'
>>> t[2][1] = 'Y'
>>> t
('a', 'b', ['X', 'Y'])
【表面上看,tuple的元素确实变了,但其实变的不是tuple的元素,而是list的元素。】
【格式化输出%s和%d】
如果你不太确定应该用什么,%s永远起作用,它会把任何数据类型转换为字符串:
>>> 'Age: %s. Gender: %s' % (25, True)
'Age: 25. Gender: True'
【当Python解释器读取源代码时,为了让它按UTF-8编码读取,我们通常在文件开头写上这两行】
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
第一行注释是为了告诉Linux/OS X系统,这是一个Python可执行程序,Windows系统会忽略这个注释;
第二行注释是为了告诉Python解释器,按照UTF-8编码读取源代码,否则,你在源代码中写的中文输出可能会有乱码。
【!】申明了UTF-8编码并不意味着你的.py文件就是UTF-8编码的,必须并且要确保文本编辑器正在使用UTF-8 without BOM编码
【互联网编码:ASCII、Unicode和UTF-8的关系】
把字符串(一种数据类型)编码为数字,才能为计算机处理;
8个比特(bit)作为一个字节(byte);
美国人发明计算机,美国人制定ASCII编码;
中国制定GB2312编码(中文至少需要两个字节),各国有各国的标准;
Unicode把所有语言都统一到一套编码里(ASCII编码和Unicode编码的区别:ASCII编码是1个字节,而Unicode编码通常是2个字节,故Unicode编码比ASCII编码需要多一倍的存储空间)【在计算机内存中,统一使用Unicode编码,当需要保存到硬盘或者需要传输的时候,就转换为UTF-8编码。】;
本着节约的精神,又出现了把Unicode编码转化为“可变长编码”的UTF-8编码(如果你要传输的文本包含大量英文字符,用UTF-8编码就能节省空间)【UTF-8编码有一个额外的好处,就是ASCII编码实际上可以被看成是UTF-8编码的一部分,所以,大量只支持ASCII编码的历史遗留软件可以在UTF-8编码下继续工作。】。