numpy中的数组相乘,是对应元素相乘;
矩阵相乘时,行列相乘后加起来,才是当前元素值;
如果A*B中的任意一项为对角数组或对角矩阵,则A*B结果相同;
1-A时,如果A是数组,则这里的1表示[[1,1,1,1,1], ..., [1,1,1,1,1]](不是单位矩阵);
如果A是矩阵,则这里的1表示对角矩阵(单位矩阵);
数组乘法默认的是点乘,矩阵默认的是矩阵乘法,混合在一起默认的是矩阵乘法;
multiply转化为对应元素的乘积,dot(d,f)会转化为矩阵的乘积;
import numpy as np
a = np.diag([1,2,3])
b = np.diag([4,5,6])
c = np.mat([[0.1,0.2,0.3],[0.4,0.5,0.6],[0.7,0.8,0.9]])
print("区分 h_stack 和 column_stack")
print(np.hstack((a, b)))
print(np.column_stack((a, b)))
print("# 区分 数组乘法 和 矩阵乘法")
print(a*c)
print(a.dot(c))
print("区分 全1矩阵(数组) 和 单位矩阵(数组)")
print(1-a)
print(np.diag([1,1,1])-a)
print("全1数组*对角数组 = 单位数组*对角数组")
print((1-a)*b)
print((np.diag([1,1,1])-a)*b)
我定义了一个嵌套字典,像一开始就初始化所有值:
dates = ['20200120', '20200121', '20200122']
dates_dic = dict(zip(dates, [{"colomn0": 0,"colomn1": 0, "colomn2": 0} for j in range(len(dates))]))
# 打印结果
print(dates_dic['20200120'])
print(dates_dic['20200120'])
dates_dic['20200120'] = 999
print(dates_dic['20200120'])
print(dates_dic['20200120'])
结果如下:
{'colomn0': 0, 'colomn1': 0, 'colomn2': 0} {'colomn0': 0, 'colomn1': 0, 'colomn2': 0} 999 999
可见,一个被赋值,所有跟着改变。
>>> os.path.exists(r"csv2\appl")
False
>>> os.path.exists(r"csv2\\appl")
False
>>> os.path.exists(r"csv2/appl")
True
任何变量的初始化赋值,要么为空(None)、要么为不可变对象(数字、元祖、字符串)。千万不要初始化为可变对象(列表,字典)。
具体原因见《改变字典中一个key的value值,另一个不相关的key-value值也被改变了》:https://blog.csdn.net/ztf312/article/details/89577328
可能出现问题:下标超出范围报错,或者返回结果不正确。
python 的列表遍历删除
a=[1,2,3,4,5,6,7]
b=[1,3,6]
for it in a:
if it not in b:
print("remove ", it)
print(a)
a.remove(it)
print(a)
remove 2
[1, 2, 3, 4, 5, 6, 7]
[1, 3, 4, 5, 6, 7]
remove 4
[1, 3, 4, 5, 6, 7]
[1, 3, 5, 6, 7]
remove 7
[1, 3, 5, 6, 7]
[1, 3, 5, 6]
如果是字典一边遍历一边删除报错,像下面这样:
# result 是一个字典, 我想把里面属性值是None的属性删除
for key in result:
if not result[key]:
result.pop(key)
continue
-----------------------------------------------------
RuntimeError: dictionary changed size during iteration # 字典在迭代的时候改变了字典大小
一个失败的尝试是,定义keys=dic.keys(),将keys独立出dic。由于函数返回值是其内部值的索引,keys仍然会随dic
变换。
成功的尝试是,使用keys=list(dic.keys())
另存一个变量,重新申请内存空间。这时遍历删除成功!
keys = list(result.keys())
for key in keys:
if not result[key]:
result.pop(key)
continue
python的内存管理机制
如果想使用input()函数输入一个数值,在得到结果后需要用int()将字符串类型转换为数值类型。
for i in range(3):
print "original:",i
i=i+3
print "new",i
original: 0
new 3
original: 1
new 4
original: 2
new 5
典型的用C语言思想,python并不买账。
>>> a=[1,2,3,1]
>>> a.remove(a[-1])
>>> a
[2, 3, 1]
>>>
如上代码,本来是想删除最后一个元素,结果误删第一个。
而对于 del 来说,它是根据索引(元素所在位置)来删除的,如下例:
>>> a=[1,2,3,1]
>>> del a[0]
>>> a
[2, 3, 1]
pop是根据索引,返回的是索引指向那个数值。
>>> a=[1,2,3,1]
>>> a.pop(2)
3
我们知道两个列表可直接相加,两个字典直接相加会报错。
于是想到一种相加方式:a.items()+b.items()。但是错误地得到了一个列表。
>>> a={1:2}
>>> b={3:4}
>>> a+b
Traceback (most recent call last):
File "", line 1, in
a+b
TypeError: unsupported operand type(s) for +: 'dict' and 'dict'
>>> c=a.items()+b.items()
>>> c
[(1, 2), (3, 4)]
>>> type(c)
正确使用方式:update()
>>> a
{1: 2}
>>> b
{3: 4}
>>> a.update(b)
>>> a
{1: 2, 3: 4}
>>> a=(1,2)
>>> (a)
(1, 2)
>>> b=[1,2]
>>> (b)
[1, 2]
>>> tuple(a)
(1, 2)
>>> tuple(b)
(1, 2)
>>> tuple([a])
((1, 2),)
这告诉我们如果需要使用元祖,最好用tuple()函数转换,而不是加括号强制转化。
>>> a=["1\t4","a\tb"]
>>> for item in a:
item = item.split("\t")
>>> a
['1\t4', 'a\tb']
>>> for i in range(len(a)):
a[i]=a[i].split("\t")
>>> a
[['1', '4'], ['a', 'b']]
列表解析总共有两种形式,很容易把二者混淆:
1. [i for i in range(k) if condition]:此时if起条件判断作用,满足条件的,将被返回成为最终生成的列表的一员。
2. [i if condition else exp for exp]:此时if...else被用来赋值,满足条件的i以及else被用来生成最终的列表。
以上情况对多个for仍然成立。
print([i for i in range(10) if i%2 == 0])
print([i if i == 0 else 100 for i in range(10)])
[0, 2, 4, 6, 8]
[0, 100, 100, 100, 100, 100, 100, 100, 100, 100]
>>> a=np.mat([[1,2,3],[4,5,6]])
>>> a
matrix([[1, 2, 3],
[4, 5, 6]])
>>> sum(a)
matrix([[5, 7, 9]])
>>> b=[[1,2,3],[4,5,6]]
>>> sum(b)
Traceback (most recent call last):
File "", line 1, in
TypeError: unsupported operand type(s) for +: 'int' and 'list'
>>> np.array(a)
array([[1, 2, 3],
[4, 5, 6]])
>>> np.array(sum(a))
array([[5, 7, 9]])
>>> np.array(sum(a))[0]
array([5, 7, 9])
>>> np.array(sum(a)[0])
array([[5, 7, 9]])
>>> b=max(np.linalg.eigvals(a))
>>> b
5.3722813232690143
>>> round(b,3)
5.3719999999999999
>>> round(b,2)
5.3700000000000001
可以看到两个问题:一室无限循环;二是精度损失;
建议不要用round(),因为它不是严格意义上的四舍五入,而是遇到5舍入时接近一个偶数;
建议用格式化表示:
>>> c = "%.4f" % b
>>> c
'5.3723'
>>> float(c)
5.3723
定义类:
import numpy as np
class ModelParams(object):
def __init__(self):
self.beta = 0.8*np.ones(NUMBER_OF_NODES)
定义对象p,并赋值给p1:
p = NodeParams()
print(">>>>test<<<<")
print(p.beta)
p1 = p
p1.beta = -1*np.ones(len(p.beta))
print(p.beta)
print(p1.beta)
输出结果(错误):
>>>>test<<<<
[ 0.8 0.8 0.8 0.8 0.8]
[-1. -1. -1. -1. -1.]
[-1. -1. -1. -1. -1.]
可以看到,对象的赋值只是传递了一个引用,改变被赋值的对象,原对象也会被改变。解决:采用深拷贝进行赋值
from copy import deepcopy
p = NodeParams()
print(">>>>test<<<<")
print(p.beta)
p1 = p
p1.beta = -1*np.ones(len(p.beta))
print(p.beta)
print(p1.beta)
输出结果(正确):
>>>>test<<<<
[ 0.8 0.8 0.8 0.8 0.8]
[ 0.8 0.8 0.8 0.8 0.8]
[-1. -1. -1. -1. -1.]
123
a=[1,2,3]
b=[4,5,6]
a+b
Out[447]: [1, 2, 3, 4, 5, 6]
a=np.array(a)
b=np.array(b)
a,b
Out[450]: (array([1, 2, 3]), array([4, 5, 6]))
a+b
Out[451]: array([5, 7, 9])
解决:用 numpy.concatenate 拼接多个数组
a=[[0,1],[2,3]]
c1=np.array(a)
c2=np.array([1,2])
c2*c1
Out[119]:
array([[0, 2],
[2, 6]])
np.mat(c2)*np.mat(c1)
Out[120]: matrix([[4, 7]])
打印矩阵(失败):
def print_matriax(M):
for i in range(len(M)):
print(",".join([str(it) for it in M[i]]))
a = np.mat([[1,2],[3,4]])
print_matriax(a)
[[1 2]]
[[3 4]]
打印数组(成功):
def print_matriax(M):
for i in range(len(M)):
print(",".join([str(it) for it in M[i]]))
a = np.array([[1,2],[3,4]])
print_matriax(a)
1,2
3,4
打印矩阵最终的解决方案(成功):
def print_matriax(M):
M = np.array(M)
for i in range(len(M)):
print(",".join([str(it) for it in M[i]]))
a = np.mat([[1,2],[3,4]])
print_matriax(a)
1,2
3,4
>>> a=np.ones(10)
>>> a
array([ 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.])
>>> a-10
array([-9., -9., -9., -9., -9., -9., -9., -9., -9., -9.])
以上案例原本是numpy的简化操作,但是实际使用中,误引入一个bug:
原本想用np.array(a)-np.array(b),结果b的计算过程出错,得到一个常数,正常应该报错,但是numpy顺利进行了减法操作,导致这个bug被忽略。
如此操作两个numpy数组会报错,因为缺少一层括号。正确为:np.concatenate((a,b), axis=0)
如此操作两个list数组会报错,因为返回append和extend返回None。正确为c=copy.deepcopy(a); c.append(b);
这里用copy.deepcopy是因为有时c不是一个单独数组,而是一个大数组中的子数组。为了避免随后改变a造成c的误变,用deepcopy保险一点。
numpy定义的数组,如果元素还是数组,会出现两种情况:(1) 子数组长度一样,为numpy.array类别。(2) 子数组长度不一样,为list类别。
a=np.array([[1,2],[3,4]])
type(a)
Out[99]: numpy.ndarray
type(a[0])
Out[100]: numpy.ndarray
b=np.array([[0, 1, 2, 3, 7, 13],[32, 33, 8, 30],[32, 33, 29, 23]])
type(b)
Out[102]: numpy.ndarray
type(b[0])
Out[103]: list
这会造成很多numpy特有函数失效,如flatten():
a.flatten()
Out[111]: array([1, 2, 3, 4])
b.flatten()
Out[112]: array([[0, 1, 2, 3, 7, 13], [32, 33, 8, 30], [32, 33, 29, 23]], dtype=object)
这里涉及到一个多维数组的概念,可能numpy认为多维数组的概念是列数相等。
回到上面的flatten()失效问题,正确的方式是采用np.hstack()函数,可成功将数组拉平。
np.hstack(b)
Out[114]: array([ 0, 1, 2, ..., 33, 29, 23])
numpy数组,必须是像矩阵一样规整的格式,子数组长度相等。
定义一个二维numpy数组,尝试将其中一个子数组定义为变量,结果将所有元素都赋值为这个变量的值了:
a=np.array([[1,2],[3,4]])
a[0]
Out[4]: array([1, 2])
a[0]=999
a
Out[6]:
array([[999, 999],
[3, 4]])
错因:加上了索引之后的标签其实指代的就是具体的存储区。见下面案例,就是指向了整个数组存储区,成功赋值:
a=[[1,2],[3,4]]
a
Out[12]: [[1, 2], [3, 4]]
a=1
a
Out[14]: 1
尝试给子数组定义为字符数组,尝试失败,无法给int()对象赋值字符串:
a=np.array([[1,2],[3,4]])
a[0]=['a','b']
Traceback (most recent call last):
File "", line 1, in
a[0]=['a','b']
ValueError: invalid literal for int() with base 10: 'a'
尝试赋值为同格式子数组,成功:
a[0]=[-1,-2]
a
Out[9]:
array([[-1, -2],
[ 3, 4]])
for i in range(len(G.nodes)):
print(G.nodes[i])
报错: keyerror: 0
原因:
G.nodes()返回类型是
G = nx.random_graphs.random_regular_graph(2,20)
G.nodes()
Out[43]: NodeView((17, 18, 7, 14, 10, 11, 8, 13, 9, 15, 4, 5, 19, 3, 1, 0, 6, 16, 12, 2))
for i in range(len(G.nodes())):
print(G.nodes[i])
{}
{}
SyntaxError: non-default argument follows default argument
案例(python3.6.3):
G.add_node(12,13):TypeError: add_node() takes 2 positional arguments but 3 were given;
G.add_node([12, 13]):TypeError: unhashable type: 'list'
G.add_node((12,13)):成功加入一个编号为(12,13)的节点
G.add_nodes_from([12,13]):成功加入两个编号为12、13的节点
G.add_edge([(1,2),(3,4)]):TypeError: add_edge() missing 1 required positional argument: 'v'
G.add_edges_from([(1,2),(3,4)]):成功加入边
不要用:import matplotlib as plt,
改用:import matplotlib.pyplot as plt
当你这样做的时候,实际上是在函数内重新定义了一个局部变量。
要想对这个全局变量成功赋值,需要重新在这个函数内部进行global的声明;
python在函数内部修改对象(结构体、数组)时,是直接改变了这个对象,无返回值也可以。
但是,在多进程中,多进程中,同一个变量,各自有一份拷贝存在于每个进程中,这是多线程和多进程最大的不同。所以如果子进程无返回值,就失去了与主进程的交互,所做修改只是局部有效。
lambda表达式中变量的作用域
>>> d = dict()
# 这里有个坑
>>> for i in range(5):
d[i] = lambda :i**2
>>> d[2]()
16
>>> d[3]()
16
# 这样看的更清楚一些
# lambda表达式中i的值是调用时决定的
>>> i = 10
>>> d[0]()
100
# 写成下面这样子就没问题了
>>> d = dict()
>>> for i in range(5):
d[i] = lambda x=i:x**2
>>> d[2]()
4
>>> d[3]()
9
坑在于,第二次调用时,如果默认参数没有被赋值,它指向第一次传入的值。
引用一个官方的经典示例地址 :
def bad_append(new_item, a_list=[]):
a_list.append(new_item)
return a_list
print(bad_append('1'))
print(bad_append('2'))
这个示例并没有按照预期打印:
['1']
['2']
而是打印了:
['1']
['1', '2']
其实这个错误问题不在默认参数上,而是我们对于及默认参数的初始化的理解有误。
照Python
哲学:
一切皆对象
函数也是一个对象,如下示例:
import types
def test():
pass
print(type(test)) #
print(isinstance(test, types.FunctionType)) # True
如此,函数就是类types.FunctionType
或者其子类的实例对象。那么对象必然有其初始化的时候,一般来说,解释器在读到函数末尾时完成函数实例的初始化。初始化后,就有了函数名到函数对象这样一个映射关系,可以通过函数名访问到函数对象了,并且,函数的一切属性也确定下来,包括所需的参数,默认参数的值。因此每次调用函数时,默认参数值是相同的(如果有默认参数)。
最佳实践
不可变的默认参数的多次调用不会造成任何影响,可变默认参数的多次调用的结果不符合预期。那么在使用可变默认参数时,就不能只在函数定义时初始化一次,而应该在每次调用时初始化。
最佳实践是定义函数时指定可变默认参数的值为None
,在函数体内部重新绑定默认参数的值。以下是对上面的两个可变默认参数示例最佳实践的应用:
def good_append(new_item, a_list = None):
if a_list is None:
a_list = []
a_list.append(new_item)
return a_list
print(good_append('1'))
print(good_append('2'))
print(good_append('c', ['a', 'b']))
dict(zip(['a','b'],[0,2]))
Out[13]: {'a': 0, 'b': 2}
dict(zip([1,1],[0,2]))
Out[14]: {1: 2}
PIL
from PIL import Image
im1 = Image.open("photo.png")
(R, G, B) = im1.split()
openvc
import cv2
im2 = cv2.imread("photo.png")
(B, G, R) = cv2.split(im2)
注意: opencv中,RGB三个通道是反过来的.
# 福利:如何用Python PIL获取图片的RGB数值
from PIL import Image
im = Image.open("xxx.jpeg")
pix = im.load()
width = im.size[0]
height = im.size[1]
for x in range(width):
for y in range(height):
r, g, b = pix[x, y]
print(r, g, b)
python中安装yaml时,应该安装pyyaml:conda install pyyaml
创建新环境:conda create -n name python=3.6.3
安装失败,提示channel不符合。
解决:
输入命令: conda update conda ”。
然后输入以下命令:conda create -n py363 python=3.6.3 anaconda ”。
成功,随后可以activate py363。
关于错误:ImportError: No module named yaml,注意:
pip install pyyaml lets you import yaml. This package enables Python to parse YAML files.
pip install pyaml lets you import pyaml. This package allows pretty-printing of YAML files
如果你用字典get方法做判断,if dic.get("key"),此处有坑。
如果key不存在,正确;
如果key存在但是dic[key]=0,此时会跳过if语句,错误.
严格的写法:
if dic.get('key', None) is not None: