zoukankan      html  css  js  c++  java
  • [转]python与numpy基础

    来源于:https://github.com/HanXiaoyang/python-and-numpy-tutorial/blob/master/python-numpy-tutorial.ipynb


    python与numpy基础

     

    寒小阳(2016年6月)

     

    Python介绍

     

    如果你问我没有编程基础,想学习一门语言,我一定会首推给你Python
    类似伪代码的书写方式,让你能够集中精力去解决问题,而不是花费大量的时间在开发和debug上
    同时得益于Numpy/Scipy这样的科学计算库,使得其有非常高效和简易的科学计算能力。
    而活跃的社区提供的各种可视化的库,也使得 机器学习/数据挖掘 的全过程(数据采集,数据清洗,数据处理,建模,可视化)可以非常流畅地完成。
    而近年来极其热门的深度学习开源框架,基本都有python接口,google的Tensorflow更是python主导。

     

    这个教程里面的内容包括:

    • 基本Python语法: 基本数据类型 (Containers, Lists, Dictionaries, Sets, Tuples), 函数, 类
    • Numpy: Arrays/数组, Array indexing/数组取值, Datatypes, Array math, Broadcasting
     

    基本python语法

     

    Python确实经常被人像伪代码,下面是一个快排程序,你可以感受一下:

    In [2]:
    def quicksort(arr):
        if len(arr) <= 1:
            return arr
        pivot = arr[len(arr) / 2]
        left = [x for x in arr if x < pivot]
        middle = [x for x in arr if x == pivot]
        right = [x for x in arr if x > pivot]
        return quicksort(left) + middle + quicksort(right)
    
    print quicksort([3,6,9, 8,10,1,2,1])
    
     
    [1, 1, 2, 3, 6, 8, 9, 10]
    
     

    基本数据类型

     

    数值型

     

    整型和浮点型以及基本的运算大家应该都知道:

    In [3]:
    x = 4
    print x, type(x)
    
     
    4 <type 'int'>
    
    In [4]:
    print x + 1   # 加;
    print x - 1   # 减;
    print x * 2   # 乘;
    print x ** 2  # 指数;
    
     
    5
    3
    8
    16
    
    In [5]:
    x += 1
    print x  # 自加
    x *= 2
    print x  # 自乘
    
     
    5
    10
    
    In [7]:
    y = 2.5
    print type(y) # 输出类型
    print y, y + 1, y * 2, y ** 2 # 连续输出
    
     
    <type 'float'>
    2.5 3.5 5.0 6.25
    
     

    不过需要提醒一句,用习惯C++和Java的同学,Python真的没有(x++)和(x--)这俩操作

     

    布尔型

     

    用于指定真假的类型,布尔型,包含真(True)和假(False):

    In [139]:
    t, f = True, False
    print type(t) # Prints "<type 'bool'>"
    
     
    <type 'bool'>
    
     

    看看逻辑与或非这些操作

    In [140]:
    print t and f # Logical AND;
    print t or f  # Logical OR;
    print not t   # Logical NOT;
    print t != f  # Logical XOR;
    
     
    False
    True
    False
    True
    
     

    字符串型

    In [142]:
    hello = 'hello'   # 实在想不出的时候就用hello world
    world = "world"
    print hello, len(hello) # 字符串长度
    
     
    hello 5
    
    In [143]:
    hw = hello + ' ' + world  # 字符串拼接
    print hw
    
     
    hello world
    
    In [144]:
    hw12 = '%s %s %d' % (hello, world, 12)  # 类似sprintf的格式化输出
    print hw12  # prints "hello world 12"
    
     
    hello world 12
    
     

    我能说什么,你面试的时候面试官最爱让你写的字符串操作,都是它自带的:

    In [26]:
    s = "hello"
    print s.capitalize()  # 首字母大写
    print s.upper()       # 全大写
    print s.rjust(7)      # 靠右对齐
    print s.center(7)     # 居中输出
    print s.replace('l', '(ell)')  # 字符串替换
    print '  world '.strip()  # 去掉两侧空白
    
     
    Hello
    HELLO
      hello
     hello 
    he(ell)(ell)o
    world
    
     

    其他你想要的字符串操作看这里.

     

    容器

     

    内置的容器用得非常非常多,包括: lists, dictionaries, sets, and tuples.

     

    Lists/列表

     

    和你学数据结构里面数组长得一样的容器,但是操作可多多了:

    In [8]:
    xs = [3, 1, 2]   # 建一个列表
    print xs, xs[2]
    print xs[-1]     # 用-1表示最后一个元素,输出来
    
     
    [3, 1, 2] 2
    2
    
    In [9]:
    xs[2] = 'Hanxiaoyang'    # 有意思的是,Python的list居然可以有不同类型的元素
    print xs
    
     
    [3, 1, 'Hanxiaoyang']
    
    In [10]:
    xs.append('happy') # 可以用append在尾部添加元素
    print xs
    
     
    [3, 1, 'Hanxiaoyang', 'happy']
    
    In [11]:
    x = xs.pop()     # 也可以把最后一个元素“弹射”出来
    print x, xs
    
     
    happy [3, 1, 'Hanxiaoyang']
    
     

    关于list更多的操作和内容可以看这里.

     

    列表切片

     

    这是大家最爱python list的原因之一,取东西太方便啦:

    In [12]:
    nums = range(5)    # 0-4
    print nums         # 输出 "[0, 1, 2, 3, 4]"
    print nums[2:4]    # 下标2到4(不包括)的元素,注意下标从0开始
    print nums[2:]     # 下标2到结尾的元素; prints "[2, 3, 4]"
    print nums[:2]     # 直到下标2的元素; prints "[0, 1]"
    print nums[:]      # Get a slice of the whole list; prints ["0, 1, 2, 3, 4]"
    print nums[:-1]    # 直到倒数第一个元素; prints ["0, 1, 2, 3]"
    nums[2:4] = [8, 9] # 也可以直接这么赋值
    print nums         # Prints "[0, 1, 8, 8, 4]"
    
     
    [0, 1, 2, 3, 4]
    [2, 3]
    [2, 3, 4]
    [0, 1]
    [0, 1, 2, 3, 4]
    [0, 1, 2, 3]
    [0, 1, 8, 9, 4]
    
     

    循环

     

    可以对list立面的元素做一个循环:

    In [13]:
    animals = ['喵星人', '汪星人', '火星人']
    for animal in animals:
        print animal
    
     
    喵星人
    汪星人
    火星人
    
     

    又要输出元素,又要输出下标怎么办,用 enumerate 函数:

    In [14]:
    animals = ['喵星人', '汪星人', '火星人']
    for idx, animal in enumerate(animals):
        print '#%d: %s' % (idx + 1, animal)
    
     
    #1: 喵星人
    #2: 汪星人
    #3: 火星人
    
     

    List comprehensions:

     

    如果对list里面的元素都做一样的操作,然后生成一个list,用它最快了,这绝对会成为你最爱的python操作之一:

    In [15]:
    # 求一个list里面的元素的平方,然后输出,很out的for循环写法
    nums = [0, 1, 2, 3, 4]
    squares = []
    for x in nums:
        squares.append(x ** 2)
    print squares
    
     
    [0, 1, 4, 9, 16]
    
     

    用list comprehension可以这么写:

    In [16]:
    nums = [0, 1, 2, 3, 4]
    # 对每个x完成一个操作以后返回来,组成新的list
    squares = [x ** 2 for x in nums]
    print squares
    
     
    [0, 1, 4, 9, 16]
    
     

    你甚至可以加条件,去筛出你想要的元素,去做你想要的操作:

    In [17]:
    nums = [0, 1, 2, 3, 4]
    # 把所有的偶数取出来,平方后返回
    even_squares = [x ** 2 for x in nums if x % 2 == 0]
    print even_squares
    
     
    [0, 4, 16]
    
     

    字典

     

    存储键值对(key => value)的数据结构, 类似Java中的Map,这真的是我使用频度相当高的数据结构:

    In [158]:
    d = {'cat': 'cute', 'dog': 'furry'}  # 建立字典
    print d['cat']       # 根据key取value
    print 'cat' in d     # 查一个元素是否在字典中
    
     
    cute
    True
    
    In [159]:
    d['fish'] = 'wet'    # 设定键值对
    print d['fish']      # 这时候肯定是输出修改后的内容
    
     
    wet
    
    In [161]:
    print d['monkey']  # 不是d的键,肯定输不出东西
    
     
    ---------------------------------------------------------------------------
    KeyError                                  Traceback (most recent call last)
    <ipython-input-161-85f0c5ba0fa7> in <module>()
    ----> 1 print d['monkey']  # KeyError: 'monkey' not a key of d
    
    KeyError: 'monkey'
    In [162]:
    print d.get('monkey', 'N/A')  # 可以默认输出'N/A'(取不到key对应的value值的时候)
    print d.get('fish', 'N/A')
    
     
    N/A
    wet
    
    In [163]:
    del d['fish']        # 删除字典中的键值对
    print d.get('fish', 'N/A') # 这会儿就没有了
    
     
    N/A
    
     

    同样的,你其他想了解的字典相关的操作和内容可以看 这里.

     

    你可以这样循环python字典取出你想要的内容:

    In [164]:
    d = {'person': 2, 'cat': 4, 'spider': 8}
    for animal in d:
        legs = d[animal]
        print 'A %s has %d legs' % (animal, legs)
    
     
    A person has 2 legs
    A spider has 8 legs
    A cat has 4 legs
    
     

    用iteritems函数可以同时取出键值对:

    In [165]:
    d = {'person': 2, 'cat': 4, 'spider': 8}
    for animal, legs in d.iteritems():
        print 'A %s has %d legs' % (animal, legs)
    
     
    A person has 2 legs
    A spider has 8 legs
    A cat has 4 legs
    
     

    Dictionary comprehensions: 和list comprehension有点像啦,但是生成的是字典:

    In [166]:
    nums = [0, 1, 2, 3, 4]
    even_num_to_square = {x: x ** 2 for x in nums if x % 2 == 0}
    print even_num_to_square
    
     
    {0: 0, 2: 4, 4: 16}
    
     

    Sets

     

    你可以理解成没有相同元素的列表(当然,显然和list是不同的):

    In [167]:
    animals = {'cat', 'dog'}
    print 'cat' in animals   # Check if an element is in a set; prints "True"
    print 'fish' in animals  # prints "False"
    
     
    True
    False
    
    In [170]:
    animals.add('fish')      # 添加元素
    print 'fish' in animals
    print len(animals)       # 元素个数
    
     
    True
    2
    
    In [171]:
    animals.add('cat')       # 如果元素已经在set里了,操作不会怎么样
    print len(animals)       
    animals.remove('cat')    # 删除一个元素
    print len(animals)
    
     
    3
    2
    
     

    循环的方式和list很像啦:

    In [63]:
    animals = {'cat', 'dog', 'fish'}
    for idx, animal in enumerate(animals):
        print '#%d: %s' % (idx + 1, animal)
    # Prints "#1: fish", "#2: dog", "#3: cat"
    
     
    #1: fish
    #2: dog
    #3: cat
    
     

    Set comprehensions: 熟悉的感觉:

    In [172]:
    from math import sqrt
    print {int(sqrt(x)) for x in range(30)}
    
     
    set([0, 1, 2, 3, 4, 5])
    
     

    元组

     

    和list很像,但是可以作为字典的key或者set的元素出现,但是一整个list不可以作为字典的key或者set的元素的:

    In [173]:
    d = {(x, x + 1): x for x in range(10)}  # Create a dictionary with tuple keys
    t = (5, 6)       # Create a tuple
    print type(t)
    print d[t]       
    print d[(1, 2)]
    
     
    <type 'tuple'>
    5
    1
    
    In [176]:
    t[0] = 1
    
     
    ---------------------------------------------------------------------------
    TypeError                                 Traceback (most recent call last)
    <ipython-input-176-0a69537257d5> in <module>()
    ----> 1 t[0] = 1
    
    TypeError: 'tuple' object does not support item assignment
     

    函数

     

    用 def 就可以定义一个函数,就像下面这样:

    In [178]:
    def sign(x):
        if x > 0:
            return 'positive'
        elif x < 0:
            return 'negative'
        else:
            return 'zero'
    
    for x in [-1, 0, 1]:
        print sign(x)
    
     
    negative
    zero
    positive
    
     

    函数名字后面接的括号里,可以有多个参数,你自己可以试试:

    In [179]:
    def hello(name, loud=False):
        if loud:
            print 'HELLO, %s' % name.upper()
        else:
            print 'Hello, %s!' % name
    
    hello('Bob')
    hello('Fred', loud=True)
    
     
    Hello, Bob!
    HELLO, FRED
    
     

     

    Python的类,怎么说呢,比较简单粗暴:

    In [76]:
    class Greeter:
    
        # 构造函数
        def __init__(self, name):
            self.name = name  # Create an instance variable
    
        # 类的成员函数
        def greet(self, loud=False):
            if loud:
                print 'HELLO, %s!' % self.name.upper()
            else:
                print 'Hello, %s' % self.name
    
    g = Greeter('Fred')  # 构造一个类
    g.greet()            # 调用函数; prints "Hello, Fred"
    g.greet(loud=True)   # 调用函数; prints "HELLO, FRED!"
    
     
    Hello, Fred
    HELLO, FRED!
    
     

    Numpy

     

    我们要开始接触高效计算库Numpy了,你要是之前在实验室用MATLAB之类的语法,你会发现Numpy和它们长得不要太像,爱MATLAB的同学,参考文档可以看这里

     

    python里面调用一个包,用import对吧, 所以我们import numpy 包:

    In [19]:
    import numpy as np
    
     

    Arrays/数组

     

    看你数组的维度啦,我自己的话比较简单粗暴,一般直接把1维数组就看做向量/vector,2维数组看做2维矩阵,3维数组看做3维矩阵...

     

    可以调用np.array去从list初始化一个数组:

    In [20]:
    a = np.array([1, 2, 3])  # 1维数组
    print type(a), a.shape, a[0], a[1], a[2]
    a[0] = 5                 # 重新赋值
    print a
    
     
    <type 'numpy.ndarray'> (3,) 1 2 3
    [5 2 3]
    
    In [198]:
    b = np.array([[1,2,3],[4,5,6]])   # 2维数组
    print b
    
     
    [[1 2 3]
     [4 5 6]]
    
    In [199]:
    print b.shape  #可以看形状的(非常常用!!!)                  
    print b[0, 0], b[0, 1], b[1, 0]
    
     
    (2, 3)
    1 2 4
    
     

    有一些内置的创建数组的函数:

    In [186]:
    a = np.zeros((2,2))  # 创建2x2的全0数组
    print a
    
     
    [[ 0.  0.]
     [ 0.  0.]]
    
    In [187]:
    b = np.ones((1,2))   # 创建1x2的全0数组
    print b
    
     
    [[ 1.  1.]]
    
    In [188]:
    c = np.full((2,2), 7) # 定值数组
    print c
    
     
    [[ 7.  7.]
     [ 7.  7.]]
    
    In [190]:
    d = np.eye(2)        # 对角矩阵(对角元素为1)
    print d
    
     
    [[ 1.  0.]
     [ 0.  1.]]
    
    In [192]:
    e = np.random.random((2,2)) # 2x2的随机数组(矩阵)
    print e
    
     
    [[ 0.09477679  0.79267634]
     [ 0.78291274  0.38962829]]
    
     

    Array indexing/数组取值

     

    Numpy提供了蛮多种取值的方式的.

     

    可以像list一样切片(多维数组可以从各个维度同时切片):

    In [203]:
    import numpy as np
    
    # 创建一个如下格式的3x4数组
    # [[ 1  2  3  4]
    #  [ 5  6  7  8]
    #  [ 9 10 11 12]]
    a = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]])
    
    # 在两个维度上分别按照[:2]和[1:3]进行切片,取需要的部分
    # [[2 3]
    #  [6 7]]
    b = a[:2, 1:3]
    print b
    
     
    [[2 3]
     [6 7]]
    
     

    虽然,怎么说呢,不建议你这样去赋值,但是你确实可以修改切片出来的对象,然后完成对原数组的赋值.

    In [202]:
    print a[0, 1]  
    b[0, 0] = 77    # b[0, 0]改了,很遗憾a[0, 1]也被修改了
    print a[0, 1]
    
     
    2
    77
    
    In [21]:
    # 创建3x4的2维数组/矩阵
    a = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]])
    print a
    
     
    [[ 1  2  3  4]
     [ 5  6  7  8]
     [ 9 10 11 12]]
    
     

    你就放心大胆地去取你想要的数咯:

    In [22]:
    row_r1 = a[1, :]    # 第2行,但是得到的是1维输出(列向量)
    row_r2 = a[1:2, :]  # 1x2的2维输出
    row_r3 = a[[1], :]  # 同上
    print row_r1, row_r1.shape 
    print row_r2, row_r2.shape
    print row_r3, row_r3.shape
    
     
    [5 6 7 8] (4,)
    [[5 6 7 8]] (1, 4)
    [[5 6 7 8]] (1, 4)
    
    In [23]:
    # 试试在第2个维度上切片也一样的:
    col_r1 = a[:, 1]
    col_r2 = a[:, 1:2]
    print col_r1, col_r1.shape
    print
    print col_r2, col_r2.shape
    
     
    [ 2  6 10] (3,)
    
    [[ 2]
     [ 6]
     [10]] (3, 1)
    
     

    下面这个高级了,更自由地取值和组合,但是要看清楚一点:

    In [220]:
    a = np.array([[1,2], [3, 4], [5, 6]])
    
    # 其实意思就是取(0,0),(1,1),(2,0)的元素组起来
    print a[[0, 1, 2], [0, 1, 0]]
    
    # 下面这个比较直白啦
    print np.array([a[0, 0], a[1, 1], a[2, 0]])
    
     
    [1 4 5]
    [1 4 5]
    
    In [221]:
    # 再来试试
    print a[[0, 0], [1, 1]]
    
    # 还是一样
    print np.array([a[0, 1], a[0, 1]])
    
     
    [2 2]
    [2 2]
    
    In [24]:
    # 再来熟悉一下
    # 先创建一个2维数组
    a = np.array([[1,2,3], [4,5,6], [7,8,9], [10, 11, 12]])
    print a
    
     
    [[ 1  2  3]
     [ 4  5  6]
     [ 7  8  9]
     [10 11 12]]
    
    In [25]:
    # 用下标生成一个向量
    b = np.array([0, 2, 0, 1])
    
    # 你能看明白下面做的事情吗?
    print a[np.arange(4), b]  # Prints "[ 1  6  7 11]"
    
     
    [ 1  6  7 11]
    
    In [218]:
    # 既然可以取出来,我们当然可以对这些元素操作咯
    a[np.arange(4), b] += 10
    print a
    
     
    [[21  2  3]
     [ 4  5 26]
     [27  8  9]
     [10 31 12]]
    
     

    比较fashion的取法之一,用条件判定去取(但是很好用):

    In [223]:
    import numpy as np
    
    a = np.array([[1,2], [3, 4], [5, 6]])
    
    bool_idx = (a > 2)  # 就是判定一下是否大于2
    
    print bool_idx  # 返回一个布尔型的3x2数组
    
     
    [[False False]
     [ True  True]
     [ True  True]]
    
    In [225]:
    # 用刚才的布尔型数组作为下标就可以去除符合条件的元素啦
    print a[bool_idx]
    
    # 其实一句话也可以完成是不是?
    print a[a > 2]
    
     
    [3 4 5 6]
    [3 4 5 6]
    
     

    那个,真的,其实还有很多细节,其他的方式去取值,你可以看看官方文档。

     

    我们一起来来总结一下,看下面切片取值方式(对应颜色是取出来的结果):

     

     

    Datatypes

     

    我们可以用dtype来看numpy数组中元素的类型:

    In [226]:
    x = np.array([1, 2])  # numpy构建数组的时候自己会确定类型
    y = np.array([1.0, 2.0])
    z = np.array([1, 2], dtype=np.int64)# 指定用int64构建
    
    print x.dtype, y.dtype, z.dtype
    
     
    int64 float64 int64
    
     

    更多的内容可以读读文档.

     

    数学运算

     

    下面这些运算才是你在科学运算中经常经常会用到的,比如逐个元素的运算如下:

    In [227]:
    x = np.array([[1,2],[3,4]], dtype=np.float64)
    y = np.array([[5,6],[7,8]], dtype=np.float64)
    
    # 逐元素求和有下面2种方式
    print x + y
    print np.add(x, y)
    
     
    [[  6.   8.]
     [ 10.  12.]]
    [[  6.   8.]
     [ 10.  12.]]
    
    In [228]:
    # 逐元素作差
    print x - y
    print np.subtract(x, y)
    
     
    [[-4. -4.]
     [-4. -4.]]
    [[-4. -4.]
     [-4. -4.]]
    
    In [229]:
    # 逐元素相乘
    print x * y
    print np.multiply(x, y)
    
     
    [[  5.  12.]
     [ 21.  32.]]
    [[  5.  12.]
     [ 21.  32.]]
    
    In [230]:
    # 逐元素相除
    # [[ 0.2         0.33333333]
    #  [ 0.42857143  0.5       ]]
    print x / y
    print np.divide(x, y)
    
     
    [[ 0.2         0.33333333]
     [ 0.42857143  0.5       ]]
    [[ 0.2         0.33333333]
     [ 0.42857143  0.5       ]]
    
    In [231]:
    # 逐元素求平方根!!!
    # [[ 1.          1.41421356]
    #  [ 1.73205081  2.        ]]
    print np.sqrt(x)
    
     
    [[ 1.          1.41421356]
     [ 1.73205081  2.        ]]
    
     

    那如果我要做矩阵的乘法运算怎么办!!!恩,别着急,照着下面写就可以了:

    In [232]:
    x = np.array([[1,2],[3,4]])
    y = np.array([[5,6],[7,8]])
    
    v = np.array([9,10])
    w = np.array([11, 12])
    
    # 求向量内积
    print v.dot(w)
    print np.dot(v, w)
    
     
    219
    219
    
    In [233]:
    # 矩阵的乘法
    print x.dot(v)
    print np.dot(x, v)
    
     
    [29 67]
    [29 67]
    
    In [234]:
    # 矩阵的乘法
    # [[19 22]
    #  [43 50]]
    print x.dot(y)
    print np.dot(x, y)
    
     
    [[19 22]
     [43 50]]
    [[19 22]
     [43 50]]
    
     

    你猜你做科学运算会最常用到的矩阵内元素的运算是什么?对啦,是求和,用 sum可以完成:

    In [235]:
    x = np.array([[1,2],[3,4]])
    
    print np.sum(x)  # 数组/矩阵中所有元素求和; prints "10"
    print np.sum(x, axis=0)  # 按行去求和; prints "[4 6]"
    print np.sum(x, axis=1)  # 按列去求和; prints "[3 7]"
    
     
    10
    [4 6]
    [3 7]
    
     

    我想说最基本的运算就是上面这个样子,更多的运算可能得查查文档.

    其实除掉基本运算,我们经常还需要做一些操作,比如矩阵的变形,转置和重排等等:

    In [236]:
    # 转置和数学公式一直,简单粗暴
    print x
    print x.T
    
     
    [[1 2]
     [3 4]]
    [[1 3]
     [2 4]]
    
    In [26]:
    # 需要说明一下,1维的vector转置还是自己
    v = np.array([1,2,3])
    print v 
    print v.T
    
    # 2维的就不一样了
    w = np.array([[1,2,3]])
    print w 
    print w.T
    
     
    [1 2 3]
    [1 2 3]
    [[1 2 3]]
    [[1]
     [2]
     [3]]
    
     

    Broadcasting

     

    这个没想好哪个中文词最贴切,我们暂且叫它“传播吧”:
    作用是什么呢,我们设想一个场景,如果要用小的矩阵去和大的矩阵做一些操作,但是希望小矩阵能循环和大矩阵的那些块做一样的操作,那急需要Broadcasting啦

    In [238]:
    # 我们要做一件事情,给x的每一行都逐元素加上一个向量,然后生成y
    x = np.array([[1,2,3], [4,5,6], [7,8,9], [10, 11, 12]])
    v = np.array([1, 0, 1])
    y = np.empty_like(x)   # 生成一个和x维度一致的空数组/矩阵
    
    # 比较粗暴的方式是,用for循环逐个相加
    for i in range(4):
        y[i, :] = x[i, :] + v
    
    print y
    
     
    [[ 2  2  4]
     [ 5  5  7]
     [ 8  8 10]
     [11 11 13]]
    
     

    这种方法当然可以啦,问题是不高效嘛,如果你的x矩阵行数非常多,那就很慢的咯:
    咱们调整一下,先生成好要加的内容

    In [240]:
    vv = np.tile(v, (4, 1))  # 重复4遍v,叠起来
    print vv                 # Prints "[[1 0 1]
                             #          [1 0 1]
                             #          [1 0 1]
                             #          [1 0 1]]"
    
     
    [[1 0 1]
     [1 0 1]
     [1 0 1]
     [1 0 1]]
    
    In [241]:
    y = x + vv  # 这样求和大家都能看明白对吧
    print y
    
     
    [[ 2  2  4]
     [ 5  5  7]
     [ 8  8 10]
     [11 11 13]]
    
     

    Numpy broadcasting allows us to perform this computation without actually creating multiple copies of v. Consider this version, using broadcasting:

    In [242]:
    import numpy as np
    
    # 因为broadcasting的存在,你上面的操作可以简单地汇总成一个求和操作
    x = np.array([[1,2,3], [4,5,6], [7,8,9], [10, 11, 12]])
    v = np.array([1, 0, 1])
    y = x + v  # Add v to each row of x using broadcasting
    print y
    
     
    [[ 2  2  4]
     [ 5  5  7]
     [ 8  8 10]
     [11 11 13]]
    
     

    当操作两个array时,numpy会逐个比较它们的shape,在下述情况下,两arrays会兼容和输出broadcasting结果:

    1. 相等
    2. 其中一个为1,(进而可进行拷贝拓展已至,shape匹配)

    比如求和的时候有:

    Image (3d array):  256 x 256 x 3
    Scale (1d array):              3
    Result (3d array): 256 x 256 x 3
    
    A      (4d array):  8 x 1 x 6 x 1
    B      (3d array):      7 x 1 x 5
    Result (4d array):  8 x 7 x 6 x 5
    
    A      (2d array):  5 x 4
    B      (1d array):      1
    Result (2d array):  5 x 4
    
    A      (2d array):  15 x 3 x 5
    B      (1d array):  15 x 1 x 5
    Result (2d array):  15 x 3 x 5
    

    下面是一些 broadcasting 的例子:

    In [243]:
    # 我们来理解一下broadcasting的这种用法
    v = np.array([1,2,3])  # v 形状是 (3,)
    w = np.array([4,5])    # w 形状是 (2,)
    # 先把v变形成3x1的数组/矩阵,然后就可以broadcasting加在w上了:
    print np.reshape(v, (3, 1)) * w
    
     
    [[ 4  5]
     [ 8 10]
     [12 15]]
    
    In [244]:
    # 那如果要把一个矩阵的每一行都加上一个向量呢
    x = np.array([[1,2,3], [4,5,6]])
    v = np.array([1,2,3])
    # 恩,其实是一样的啦
    print x + v
    
     
    [[2 4 6]
     [5 7 9]]
    
    In [245]:
    x = np.array([[1,2,3], [4,5,6]]) # 2x3的
    w = np.array([4,5])    # w 形状是 (2,)
    
    # 自己算算看?
    print (x.T + w).T
    
     
    [[ 5  6  7]
     [ 9 10 11]]
    
    In [246]:
    # 上面那个操作太复杂了,其实我们可以直接这么做嘛
    print x + np.reshape(w, (2, 1))
    
     
    [[ 5  6  7]
     [ 9 10 11]]
    
    In [247]:
    # broadcasting当然可以逐元素运算了
    print x * 2
    
     
    [[ 2  4  6]
     [ 8 10 12]]
    
     

    总结一下broadcasting,可以看看下面的图:

     

    更多的numpy细节和用法可以查看一下官网numpy指南

  • 相关阅读:
    分享:两个栈实现一个队列的功能
    分享:要关注技术,但也要关注所做的事情
    linux网络编程中阻塞和非阻塞socket的区别
    分享:C++参数传递方式
    linux非阻塞socket教程
    有用和有趣的产品秤砣
    查找 grep r TFramedTransport *
    分享:SecureCRT使用VIM语法高亮
    linux 非阻塞 socket Google 搜索
    linux c语言 select函数用法 ITeye技术网站
  • 原文地址:https://www.cnblogs.com/wuxiangli/p/7225116.html
Copyright © 2011-2022 走看看