zoukankan      html  css  js  c++  java
  • Numpy_01

    # 引子:
    
    # ndarray 是一个 numpy库提供的 同构数据多维模型
    import numpy as np
    
    list=[1,2,3,4,5,6]
    myndarray=np.array(list)
    # type(myndarray)  # numpy.ndarray
    # myndarray.dtype  # dtype('int32')
    # print(myndarray) # [1 2 3 4 5 6]
    # print(myndarray.shape) # (7,1)
    myndarray  
    # array([1,
    #       2, 
    #       3, 
    #       4, 
    #       5, 
    #       6])   #7行1列数据
    
    array([1, 2, 3, 4, 5, 6])
    
    # numpy的基本用法:
    
    # 一,创建 ndarray:
    # 1)np.array()方法: 接收一切序列类型对象,包括其他数组。
    # 2)其他方法,如:np.zeros(),np.ones(),np.empty(),np.arange(),np.ones_like(),np.zeros_like(),
    # np.eye(),np.empty_like(),np.identity()等。
    
    # 1--ndarray的 基本属性:
    import numpy as np
    mylist=[1,2,3,4,5]
    myarray=np.array(mylist)
    print(myarray)            # [1 2 3 4 5]  矩阵
    
    print(myarray.ndim)       # 1      维数
    print(myarray.size)       # 5      元素总数
    print(myarray.shape)      # (5,)   形状     一维数组的形状 (n,)或(1,n)
    print(myarray.dtype)      # int32  数据类型
    print(myarray.itemsize)   # 4      每个元素的字节大小  32位/8位(每字节)=4 字节
    
    # 2--特殊的 ndarray:
    # 2.1--np.zeros()函数:
    np.zeros(5)       # array([0., 0., 0., 0., 0.])
    np.zeros((2,3))
    
    # 2.2--np.ones()函数:
    np.ones(5)       # array([1., 1., 1., 1., 1.])
    np.ones((2,3))    
    
    # 2.3--np.empty()函数:
    # empty函数可以创建一个没有具体值的数组(即垃圾值):
    np.empty((2,2))     # 认为np.empty返回全0数组是不安全的,很多情况下,返回的都是一些未初始化的垃圾值,比如:
    # array([[1.14800323e-311, 6.95177601e-310],
    #        [6.95177601e-310, 1.14898595e-311]])
    
    # 2.5--np.ones_like()函数和np.zeros_like()函数:
    arr01=np.array([[1,2,3,4],[5,6,7,8]])
    arro1
    # array([[1, 2, 3, 4],
    #       [5, 6, 7, 8]])
    
    arr02=np.zeros_like(arr01)
    arr02
    # array([[0, 0, 0, 0],
    #       [0, 0, 0, 0]])
    
    arr03=np.ones_like(arr01)
    arr03
    # array([[1, 1, 1, 1],
    #       [1, 1, 1, 1]])
    
    arr04=np.array([["a",1,"s"],["c",2,"v"]])
    arr04
    # array([['a', '1', 's'],
    #       ['c', '2', 'v']], dtype='<U1')
    
    arr05=np.ones_like(arr04)
    arr05
    # array([['1', '1', '1'],
    #        ['1', '1', '1']], dtype='<U1')
    
    # 2.6--np.arange()函数:模仿指定的ndarray创建全1或全0数组。
    # arange函数类似于python的内置函数range,但arange函数主要用于创建数组。
    np.arange(5)      # array([0, 1, 2, 3, 4])
    np.arange(1,5)    # array([ 1, 2, 3, 4])
    np.arange(1,10,2) # array([1, 3, 5, 7, 9])
    
    # 2.7--np.eye()函数,np.empty_like()函数,np.identity()函数, np.asarray()函数:
    # 用到再来学习。
    
    # 二,ndarray 的数据类型
    
    # Numpy既可以为新建的数组【推断】出合适的数据类型,也可以通过【dtype属性来指定类型】。
    # Numpy有很多数据类型,记住下面这些常用的就可以:
    # folat   int   complex复数    bool布尔     string_     python对象:object
    # 各数据类型及代码以及数据类型的解释见《利用python及逆行数据分析(2)》p121
    
    # 1--数据类型推断:
    arr01=np.array([0,1,2,3,4])
    arr01.dtype  # dtype('int32')
    
    
    # 2--为数组指定数据类型时:
    arr01=np.array([0,1,2,3,4],dtype='float64')
    arr01.dtype  # dtype('folat64')
    arr02=np.arange(10,dtype='float')
    arr02.dtype  # dtype('float64')
    
    
    # 3--使用astype显示转换数据类型,不改变原数组,返回一个新数组:
    # 语法:newarr=arr.astype([np.]数据类型)方法 或 newarr=arr.astype(arr2.dtype)方法  使用其他数组的dtype作为参数。
    
    # 3-1)将数值型转为字符串:
    arr01=np.array([0,1,2,3,4],dtype='float64')
    arr02=arr01.astype(np.string_)
    arr01.dtype    # dtype('float64')
    arr02.dtype    # dtype('S32')
    
    # 3-2)将浮点型数组转为整数,并不会四舍五入,而是直接截断
    arr01=np.array([0,1,2.5,3.1,4.2],dtype='float64')
    arr02=arr01.astype(np.int32)
    arr02.dtype  #dtype('int32')
    arr02 # array([0, 1, 2, 3, 4])
    
    # 3-3)将字符串型的数字的数组转成数值类型:
    arr01=np.array(['0','1','2.5','3.1','4.2'])
    arr02=arr01.astype(np.float64)
    arr02        # array([0. , 1. , 2.5, 3.1, 4.2])
    arr02.dtype  # dtype('float64')
    
    # 如果数组里有字符型字符串,使用astype转为数值就会报错:
    arr01=np.array(['a','1','e','3.1','4.2'])
    arr02=arr01.astype(np.float64) #ValueError: could not convert string to float: 'a'
    arr02
    
    # 3-4)使用其他数组的数据类型   newarr=arr.astype(arr2.dtype)方法 
    arr01=np.array([0,1,2,3,4],dtype='float64')
    arr02=np.array(["1","4","5"])
    arr03=arr02.astype(arr01.dtype)
    arr03.dtype
    
    # 三,数组和标量之间的运算 (+ - * /  **)
    # 数组之所以很重要,是因为它不需要编写循环就可以对数组内每一个数据元素进行运算,通常称之为矢量化。
    # -- 不同大小的数组之间的运算叫做广播,这里不对广播机制做深入了解。
    # -- 大小相等的数组之间的任何算术运算都会将运算应用到元素级:
    
    # 1--数组准备
    arr=np.array([[1.,2.,3.],[4.,5.,6.]])   # 或 arr=np.arange(1.0,7.0).reshape(2,3)
    arr
    # array([[1., 2., 3.],
    #        [4., 5., 6.]])
    
    # 2--数组与数组:
    # 2-1)数组×数组
    arr*arr
    # array([[ 1.,  4.,  9.],
    #        [16., 25., 36.]])
    
    # 2-2)数组-数组
    arr-arr
    # array([[0., 0., 0.],
    #        [0., 0., 0.]])
    
    # 3--数组与标量:
    1/arr
    # array([[1.        , 0.5       , 0.33333333],
    #        [0.25      , 0.2       , 0.16666667]])
    
    arr**2
    # array([[ 1.,  4.,  9.],
    #        [16., 25., 36.]])
    
    arr-0.5
    # array([[0.5, 1.5, 2.5],
    #        [3.5, 4.5, 5.5]])
    
    # 4--数组与标量的混合运算
    3*arr+2
    # array([[ 5.,  8., 11.],
    #        [14., 17., 20.]])
    
    # 5--数组元素比较, 返回布尔值类型数组
    arr2 = np.array([[0., 4., 1.], [7., 2., 12.]])
    arr>arr2
    # array([[ True, False,  True],
    #        [False,  True, False]])
    
    # 四,基本索引和切片
    
    # Numpy 数组的索引方法非常多。
    
    # 1 一维数组的元素索引和数组切片:
    
    # 1)一维数组元素的访问:
    arr=np.arange(10)
    arr[5]  # 5
    
    # 2)一维数组的切片:
    arr[5:8]
    array([5, 6, 7])
    
    # 3)一维数组切片赋值:
    # 会影响原数组(数组的切片是原数组的视图,这和python的list切片是原list的浅复制不同)之所以会这样,是因为Numpy是为大数据考虑的,
    # 如果不是在原数组上操作,而是复制来复制去,会非常占用内存。
    arr[3:7]=0          # 或: arr_slice=arr[3:7]  arr_slice=0
    arr                 # array([ 0,  1,  2, 0, 0, 0, 0,  7,  8,  9])
    arr_slice2=arr[6:9]
    arr_slice2[0]=9999  # 改变切片的第一个元素值
    arr_slice2[1:]=8888
    arr                 #  array([   0,    1,    2,   0,   0,   0, 9999, 8888, 8888,    9])
    
    # 4)一维数组切片的显式复制(浅复制):
    # 语法:arr[5:8].copy()  
    arr=np.arange(10)
    arr2=arr[5:8].copy()
    arr2[:]=777
    arr2  # array([777, 777, 777])
    arr   # array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])  原数组没变
    
    
    # 2 高维(二维)数组元素的索引和切片:  三维数组暂时不需要考虑
    # 1) 创建一个二维数组  (3,3) 
    arr2d=np.arange(1,10).reshape(3,3) 
    arr2d
    # array([[1, 2, 3],
    #        [4, 5, 6],
    #        [7, 8, 9]])
    
    # 1-1)二维数组的元素索引:
    arr2d[2]
    array([7, 8, 9])
    arr2d[2][1]  # 或
    arr2d[2,1]   8
    
    # 1-2)二维数组的切片:
    arr2d[:2]     # 沿着0轴选取元素
    # array([[1, 2, 3],
    #        [4, 5, 6]])
    arr2d[:2].shape  #
    # (2,3) 二维数组
    
    arr2d[:2,1:]    
    # array([[2, 3],
    #        [5, 6]])
    arr2d[:2,1:].shape 
    # (2,2)
    
    arr2d[:,1]  
    # array([2, 5, 8])
    arr2d[:,1].shape  
    # (3,)  一维数组
    
    arr2d[:,:1]
    array([[1],
           [4],
           [7]])
    arr2d[:,:1].shape  
    #(3, 1) 二维数组
    
    #当然,对切片的赋值也会影响到原数组:
    arr2d[:,:1]=9
    arr2d
    array([[9, 2, 3],
           [9, 5, 6],
           [9, 8, 9]])
    
    # 五,布尔索引
    
    # 示例:
    # 数组1:一个用于存储数据的数组以及一个存储姓名的数组(含有重复项)。
    # 数组2:使用np.random中的 randn函数生成一些正态分布的随机数据。
    # 1)生成数组1 names :
    names=np.array(["Bob","Joe","Will","Bob","Will","joe","joe"])
    names  # array(['Bob', 'Joe', 'Will', 'Bob', 'Will', 'joe', 'joe'], dtype='<U4')
    # 2) 生成 数组2 data:
    data=np.random.randn(7,4)
    data
    array([[ 0.13914193, -0.96275352,  0.35075216,  0.25364798],
           [-1.10364635, -0.2635838 , -0.84638153,  0.67202326],
           [-0.83869909, -0.06954938,  0.80021281, -2.44477926],
           [-0.08734994, -0.08249876,  0.07469813,  0.27376429],
           [ 1.0876769 ,  1.45565495, -2.602985  , -0.89583722],
           [-0.24046131,  0.68823067, -0.34271733, -1.67964804],
           [ 0.12394175,  2.32313088,  0.23627141,  1.7670217 ]])
    
    # 1--获取一个布尔数组,并使用布尔数组获取另一个数组的数组切片:
    
    # 1)等号==的使用
    # 假设names 中每一个名字都对应 data中的每行数据,现在我们要选出对应于‘Bob’的每一行数据。
    bool_Bob = names == 'Bob'  # names == 'Bob'  返回一个布尔类型的数组, ==在数组中也是矢量化的。
    bool_Bob
    # array([ True, False, False,  True, False, False, False])
    # np.array([ True, False, False,  True, False, False, False]).shape  # (7,)
    # data.shape  # (7,4)
    
    # 将这个布尔数组作为 data 数组的索引: #【布尔型数组的长度】必须和【被索引的轴】长度一致。
    data[names == 'Bob']      # 相当于:data[ True, False, False, True, False, False, False]  或 data[bool_Bob]
    array([[ 0.13914193, -0.96275352,  0.35075216,  0.25364798], [-0.08734994, -0.08249876,  0.07469813,  0.27376429]])
    
    
    # 还可以将布尔型数组与切片,整数(或整数序列)混合使用:
    data[names=='Bob',2:]  # 与切片混合使用,第3列及以后列
    array([[ 0.20745417,  1.59998866],
           [-1.54179944,  0.26520684]])
    data[names=='Bob',3]  # 与整数混合使用,第4列
    array([0.59981237, 2.19444112])
    
    # 2)不等号!=的使用:
    data[names!='Bob']
    array([[-1.52854216,  0.25771145, -1.23529507,  0.18793414],
           [-0.16193399, -0.51354289,  1.90586211, -0.58838872],
           [ 0.47066932,  1.69033558, -0.47329781, -0.01530668],
           [ 1.23895961, -1.91537102, -1.50733678,  0.16473193],
           [-0.59033351,  0.36576441,  2.36265923, -1.1060814 ]])
    
    # 3) ~和==的联用,效果同 !=:
    data[~(names=='Bob')]
    array([[-1.52854216,  0.25771145, -1.23529507,  0.18793414],
           [-0.16193399, -0.51354289,  1.90586211, -0.58838872],
           [ 0.47066932,  1.69033558, -0.47329781, -0.01530668],
           [ 1.23895961, -1.91537102, -1.50733678,  0.16473193],
           [-0.59033351,  0.36576441,  2.36265923, -1.1060814 ]])
    # 4)逻辑或 |的使用(别忘了使用()):  python中的 or 在数组里是无效的
    mask=(names=='Bob')|(names=='Will')
    mask
    array([ True, False,  True,  True,  True, False, False])
    data[mask]
    array([[ 0.9965483 , -0.88256842, -0.12551621,  0.59981237],
           [-0.16193399, -0.51354289,  1.90586211, -0.58838872],
           [ 0.28340236, -0.93341777, -0.48931644,  2.19444112],
           [ 0.47066932,  1.69033558, -0.47329781, -0.01530668]])
    
    # 5)逻辑与 & 的使用: python中的 and 在数组中是无效的
    mask=(names=='Bob')&(names=='Will')  
    # names中元素的值是确定的,不可能既是‘Bob’又是的'Will',所以可以预想 mask 的元素全是False
    mask
    data[mask]  # 空数组
    array([], shape=(0, 4), dtype=float64)
    
    
    # 2--通过布尔型索引来选取数组中所有符合条件的元素数据,并改变这些元素的值:
    data[data<0]
    array([-0.96275352, -1.10364635, -0.2635838 , -0.84638153, -0.83869909,
           -0.06954938, -2.44477926, -0.08734994, -0.08249876, -2.602985  ,
           -0.89583722, -0.24046131, -0.34271733, -1.67964804])   # 它的 shape是(14,) 一维数组
    data[data<0]=0  # 对切片进行赋值
    data  # 从而改变原数组:
    array([[0.13914193, 0.        , 0.35075216, 0.25364798],
           [0.        , 0.        , 0.        , 0.67202326],
           [0.        , 0.        , 0.80021281, 0.        ],
           [0.        , 0.        , 0.07469813, 0.27376429],
           [1.0876769 , 1.45565495, 0.        , 0.        ],
           [0.        , 0.68823067, 0.        , 0.        ],
           [0.12394175, 2.32313088, 0.23627141, 1.7670217 ]])
    
    data[data==0]=0.1  
    data
    array([[0.13914193, 0.1       , 0.35075216, 0.25364798],
           [0.1       , 0.1       , 0.1       , 0.67202326],
           [0.1       , 0.1       , 0.80021281, 0.1       ],
           [0.1       , 0.1       , 0.07469813, 0.27376429],
           [1.0876769 , 1.45565495, 0.1       , 0.1       ],
           [0.1       , 0.68823067, 0.1       , 0.1       ],
           [0.12394175, 2.32313088, 0.23627141, 1.7670217 ]])
    
    data[(data==0.1)|(data<0.2)]=0.25  # 别忘了加()
    data
    array([[0.25      , 0.25      , 0.35075216, 0.25364798],
           [0.25      , 0.25      , 0.25      , 0.67202326],
           [0.25      , 0.25      , 0.80021281, 0.25      ],
           [0.25      , 0.25      , 0.25      , 0.27376429],
           [1.0876769 , 1.45565495, 0.25      , 0.25      ],
           [0.25      , 0.68823067, 0.25      , 0.25      ],
           [0.25      , 2.32313088, 0.23627141, 1.7670217 ]])
    
    
    # 3--通过布尔型索引来选取数组中所有符合条件的行或列数据,并改变这些行或列的值:
    # 1)为整行赋值:
    data[names=='joe']=7
    data
    array([[0.25      , 0.25      , 0.35075216, 0.25364798],
           [0.25      , 0.25      , 0.25      , 0.67202326],
           [0.25      , 0.25      , 0.80021281, 0.25      ],
           [0.25      , 0.25      , 0.25      , 0.27376429],
           [1.0876769 , 1.45565495, 0.25      , 0.25      ],
           [7.        , 7.        , 7.        , 7.        ],
           [7.        , 7.        , 7.        , 7.        ]])
    # 2)为整列赋值:
    bool_arr=np.array([False,False,True,False])
    data=data.swapaxes(0,1)  # 先把 data 数组轴对换返回的是一个新的数组赋值给 data。
    data[bool_arr]=100       # 为新数组data的行赋值,相当于为旧数组的列赋值。
    data=data.swapaxes(0,1)  # 将 data再次转回来。
    data
    array([[  0.25      ,   0.25      , 100.        ,   0.25364798],
           [  0.25      ,   0.25      , 100.        ,   0.67202326],
           [  0.25      ,   0.25      , 100.        ,   0.25      ],
           [  0.25      ,   0.25      , 100.        ,   0.27376429],
           [  1.0876769 ,   1.45565495, 100.        ,   0.25      ],
           [  7.        ,   7.        , 100.        ,   7.        ],
           [  7.        ,   7.        , 100.        ,   7.        ]])
    
    # 六,花式索引(整数数组索引)
    
    # 与切片的一个很大不同点是,它总是将数据复制到新数组中,对花式索引结果的赋值,不影响原数组,因为其形状与原数组都不一样了,
    # 自然没法赋值给原数组。
    
    # 1) 首先准备一个8x4的数组:
    arr84=np.empty((8,4))
    for i in range(8):
        arr84[i]=i  # 为每一行赋一个值
    arr84
    array([[0., 0., 0., 0.],
           [1., 1., 1., 1.],
           [2., 2., 2., 2.],
           [3., 3., 3., 3.],
           [4., 4., 4., 4.],
           [5., 5., 5., 5.],
           [6., 6., 6., 6.],
           [7., 7., 7., 7.]])
    
    # 2) 使用指定顺序的【整数列表】或【ndarray】作为索引来选取特定顺序的子集:
    # 2-1)使用一个整数【列表】作为索引 (注意索引为列表,如果少了[]就会报错: IndexError: too many indices for array)
    
    arr84[[4,3,0,6]]  # 取arr84数组的第5,第4,第1和第7行数据
    array([[4., 4., 4., 4.],
           [3., 3., 3., 3.],
           [0., 0., 0., 0.],
           [6., 6., 6., 6.]])
    arr84[[-3,-5,-7]]  #使用负的索引,会从数组的末尾开始选行,-3表示倒数第三行。
    array([[5., 5., 5., 5.],
           [3., 3., 3., 3.],
           [1., 1., 1., 1.]])
    
    # 2-2)使用多个整数列表作为索引:  返回一维数组  
    # 分别从各个整数列表里各自选出对应元素组成位置元组 进行索引后组成一维数组
    # 1)先准备一个数组:
    newarr84=np.arange(32).reshape((8,4))
    newarr84
    array([[ 0,  1,  2,  3],
           [ 4,  5,  6,  7],
           [ 8,  9, 10, 11],
           [12, 13, 14, 15],
           [16, 17, 18, 19],
           [20, 21, 22, 23],
           [24, 25, 26, 27],
           [28, 29, 30, 31]])
    # 2)对于二维数组的花式索引最多可以使用两个整数列表:
    # 对于二维数组,最多可用两个整数列表,列表的长度可不定,但两个列表的长度要保持一致,
    # 第一个列表的【每个整数值】不能超过 0轴(行,第1维)的长度,第二个列表的【每个整数值】不能超过 1轴(列,第二维)的长度。
    newarr84[[1,5,7,2],[0,3,1,2]]   # array([4,23,29,10])
    newarr84[[1,5,7,2,5],[0,3,1,2,1]]  # array([4,23,29,10,21])
    
    # 3)如果你想得到的不是一维数组,而是一个包含上述元素且按照上述元素出现顺序的矩形区域,那么可以使用下面两种方法:
    # 此矩形区域的行数和列数都可以和原数组不同。
    # 3-1):
    newarr84[[1,5,7,2]][:,[0,3,1,2]]            # 4x4  分开写:new=newarr84[[1,5,7,2]],new2=new[:,[0,3,1,2]]   输出new2
    # 另一种写法:newarr84[np.ix_([1,5,7,2],[0,3,1,2])]
    array([[ 4,  7,  5,  6],
           [20, 23, 21, 22],
           [28, 31, 29, 30],
           [ 8, 11,  9, 10]])
    
    newarr84[[1,5,7,2,5]][:,[0,3,1,2,1]]      # 5x5 分开写:new=newarr84[[1,5,7,2,5]],new2=new[:,[0,3,1,2,1]]   输出new2
    # 另一种写法:newarr84[np.ix_([1,5,7,2,5],[0,3,1,2,1])]
    array([[ 4,  7,  5,  6,  5],
           [20, 23, 21, 22, 21],
           [28, 31, 29, 30, 29],
           [ 8, 11,  9, 10,  9],
           [20, 23, 21, 22, 21]])
    
    # 对花式索引的结果赋值,不影响原来的数组。
    newarr84[np.ix_([1,5,7,2],[0,3,1,2])]=0
    newarr84[np.ix_([1,5,7,2],[0,3,1,2])]
    array([[0, 0, 0, 0],
           [0, 0, 0, 0],
           [0, 0, 0, 0],
           [0, 0, 0, 0]])
    newarr84
    array([[ 0,  1,  2,  3],
           [ 0,  0,  0,  0],
           [ 0,  0,  0,  0],
           [12, 13, 14, 15],
           [16, 17, 18, 19],
           [ 0,  0,  0,  0],
           [24, 25, 26, 27],
           [ 0,  0,  0,  0]])
    
    # 七,数组转置和轴对换
    # 转置是重塑的一种特殊形式,返回的是原数组的视图(不会进行任何复制操作)
    # arr和arr.T ,arr.transpose() 都是arr的不同形式,对arr.T ,arr.transpose(),array.swapaxes()的赋值操作都会影响arr
    # 1)array.T 属性  2)array.transpose()方法  3)array.swapaxes()方法
    
    # 对于二维数组:
    arr35=np.arange(15).reshape((3,5))
    arr35
    array([[ 0,  1,  2,  3,  4],
           [ 5,  6,  7,  8,  9],
           [10, 11, 12, 13, 14]])
    
    # 1)array.T 属性:
    arr35.T
    array([[ 0,  5, 10],
           [ 1,  6, 11],
           [ 2,  7, 12],
           [ 3,  8, 13],
           [ 4,  9, 14]])
    arr35  # arr35还是arr35
    array([[ 0,  1,  2,  3,  4],
           [ 5,  6,  7,  8,  9],
           [10, 11, 12, 13, 14]])
    
    arr35.T[1]=-1  # 对转置后的第二行进行赋值:
    arr35.T
    array([[ 0,  5, 10],
           [-1, -1, -1],
           [ 2,  7, 12],
           [ 3,  8, 13],
           [ 4,  9, 14]])
    arr35  
    array([[ 0, -1,  2,  3,  4],
           [ 5, -1,  7,  8,  9],
           [10, -1, 12, 13, 14]])
    
    # 来做个计算矩阵内积的示例:np.dot   即矩阵的点乘
    arr35=np.arange(15).reshape((3,5))
    arrdot=np.dot(arr35.T,arr35)
    arrdot
    array([[125, 140, 155, 170, 185],
           [140, 158, 176, 194, 212],
           [155, 176, 197, 218, 239],
           [170, 194, 218, 242, 266],
           [185, 212, 239, 266, 293]])
    
    
    # 2) arr.transpose(轴号元组)
    # 对于二维数组:
    arr35=np.arange(15).reshape((3,5))
    arr35.transpose((1,0))
    array([[ 0,  5, 10],
           [ 1,  6, 11],
           [ 2,  7, 12],
           [ 3,  8, 13],
           [ 4,  9, 14]])
    arr35
    array([[ 0,  1,  2,  3,  4],
           [ 5,  6,  7,  8,  9],
           [10, 11, 12, 13, 14]])
    
    arr35=np.arange(15).reshape((3,5))
    arr35.transpose((1,0))[0]=-6
    arr35
    array([[-6,  1,  2,  3,  4],
           [-6,  6,  7,  8,  9],
           [-6, 11, 12, 13, 14]])
    
    
    # 3)array.swapaxes(一对要对换的轴编号)方法, 参数是两个轴号,不是元组。 
    arr35=np.arange(15).reshape((3,5))
    arr35.swapaxes(0,1)  # 也可 arr35.swapaxes(1,0)
    array([[ 0,  5, 10],
           [ 1,  6, 11],
           [ 2,  7, 12],
           [ 3,  8, 13],
           [ 4,  9, 14]])
    arr35
    array([[ 0,  1,  2,  3,  4],
           [ 5,  6,  7,  8,  9],
           [10, 11, 12, 13, 14]])
    
    arr35.swapaxes(0,1)[0]=-2
    arr35
    array([[-2,  1,  2,  3,  4],
           [-2,  6,  7,  8,  9],
           [-2, 11, 12, 13, 14]])
    

    arr35

    # 八,通用函数 ufunc:快速的元素级的数组函数
    # 可以看作是简单函数(接受一个或多个标量值,并产生一个或多个标量值)的矢量化包装器。
    # 许多ufunc都是简单的元素级变体,如sqrt,exp:
    
    # 一元 ufunc:
    # abs,fabs--计算整数,浮点数,复数的绝对值,对于非复数值,可以使用更快的fabs
    # sqrt------计算各元素的平方根,相当于arr**0.5
    # square----计算各元素的平方,相当于arr**2
    # exp-------计算各元素的以e为底的指数
    # log,log10,log2,log1p--分别表示自然对数,底数为10的log,底数为2的log,log(1+x)
    # sign--计算各元素的正负号:1(正数),0(零),-1(负数)
    # ceil--计算各元素的ceiling值,即大于等于该值的最小整数。 (天花板值)
    # floor--计算该值的floor值,即小于等于该值的最大整数。(地板值)
    # rint--将各元素的值四舍五入到最接近的整数,保留dtype。
    # modf--将数组的小数和整数部分以两个独立数组的形式返回。
    # isnan--返回一个表示哪些值是 NAN (not a number)的布尔型数组
    # isfinite--返回一个表示哪些元素是有尽的(非inf,非NAN)的布尔型数组
    # isinf--返回一个表示哪些元素是无穷的的布尔型数组
    # cos,cosh,sin,sinh,tan,tanh--普通型和双曲型三角函数
    # arccos,aeccosh,arcsin,arcsinh,arctan,arctanh--反三角函数
    # logicl-not--计算各元素not x的真值。相当于 -arr
    
    # 二元ufunc:
    # add--将两个数组中对应的元素相加
    # subtract--将两个数组中对应的元素相减
    # multiply--将两个数组中对应的元素相乘
    # devide,floor_divide--除法或向下圆整除法(丢弃余数)
    # power--对于第一个数组中的元素A,根据第二个数组中的相应的元素B,计算A**B
    # maximum,fmax--元素级的最大值计算,fmax将忽略NAN
    # minimum,fmin--元素级的最小值计算,fmin将忽略NAN
    # mod--元素级的取模计算(除法的余数)余数。
    # copysign--将第二个数组中的符号复制给第一个数组中的值
    # greater、greater_equal、less、less_equal、equal、not equal--执行数组元素的比较运算,产生布尔型数组。相当于中辍运算符 >,>=,<,<=,==,!=
    # logical_and、logical_or、logical_xor--执行元素级的真值逻辑运算。相当于中辍运算符 &、|、^
    
    
    # 示例:
    
    # 一元ufunc函数示例:
    # 1)np.sqrt(arr)  计算每个元素的平方根
    arr=np.arange(10)
    np.sqrt(arr)
    array([0.        , 1.        , 1.41421356, 1.73205081, 2.        ,
            2.23606798, 2.44948974, 2.64575131, 2.82842712, 3.        ])
    
    # 2)np.exp(arr)  计算各元素的以e为底的指数
    np.exp(arr)
    array([1.00000000e+00, 2.71828183e+00, 7.38905610e+00, 2.00855369e+01,
            5.45981500e+01, 1.48413159e+02, 4.03428793e+02, 1.09663316e+03,
            2.98095799e+03, 8.10308393e+03])
    
    # 3) np.modf(arr)  将数组的小数和整数部分以两个独立数组的形式返回
    # 会返回两个数组(返回两个数组的ufunc比较少),它是python内置函数divmod的矢量化版本。
    arrfloat=np.random.randn(7)*5
    np.modf(arrfloat)
    (array([ 0.06999584,  0.51758053, -0.46226613, -0.26251269,  0.36295513,
                0.84655061, -0.43529079]),
    array([ 4.,  1., -6., -3.,  5.,  1., -2.]))
    
    
    # 二元ufunc函数示例:
    arr1=np.random.randn(8)
    arr2=np.random.randn(8)
    
    # 1)np.add(arr1,arr2)  对应位置元素求和
    arr1
    array([-0.11423455,  0.34311356,  0.97609564,  0.43885802,  1.61820549,
            -1.21456404, -0.62405483, -1.37193806])
    arr2
    array([-0.01736506,  1.5373613 ,  1.3406096 , -0.20445385,  0.22836248,
             -1.95019508,  1.39529547,  0.39184623])
    
    np.add(arr1,arr2)
    array([-0.13159961,  1.88047485,  2.31670524,  0.23440417,  1.84656797,
            -3.16475912,  0.77124064, -0.98009183])
    
    # 2)np.maximum(arr1,arr2)  对应位置元素取较大值
    np.maximum(arr1,arr2)
    array([-0.01736506,  1.5373613 ,  1.3406096 ,  0.43885802,  1.61820549,
            -1.21456404,  1.39529547,  0.39184623])
    
    # 九,使用数组进行面向数组编程
    
    # 9.1--假设我们想得到一组值(网格型)上计算sqrt(x^2+y^2)。np.meshingrid(arr1,arr2)函数接受两个一维数组,并产生两个二维矩阵
    # 假设一维数组的长度为n,那么二维数组的shape为(n,n)
    #(对应于两个数组中所有的(x,y)对):
    points=np.arange(-5,5,0.01)       # 一维数组   
    xs,ys=np.meshgrid(points,points)  # xs,ys均为二维数组, 
    xs
        array([[-5.  , -4.99, -4.98, ...,  4.97,  4.98,  4.99],
               [-5.  , -4.99, -4.98, ...,  4.97,  4.98,  4.99],
               [-5.  , -4.99, -4.98, ...,  4.97,  4.98,  4.99],
               ...,
               [-5.  , -4.99, -4.98, ...,  4.97,  4.98,  4.99],
               [-5.  , -4.99, -4.98, ...,  4.97,  4.98,  4.99],
               [-5.  , -4.99, -4.98, ...,  4.97,  4.98,  4.99]])
    ys
    
        array([[-5.  , -5.  , -5.  , ..., -5.  , -5.  , -5.  ],
               [-4.99, -4.99, -4.99, ..., -4.99, -4.99, -4.99],
               [-4.98, -4.98, -4.98, ..., -4.98, -4.98, -4.98],
               ...,
               [ 4.97,  4.97,  4.97, ...,  4.97,  4.97,  4.97],
               [ 4.98,  4.98,  4.98, ...,  4.98,  4.98,  4.98],
               [ 4.99,  4.99,  4.99, ...,  4.99,  4.99,  4.99]])
    
    
    # 现在对函数的求值运算就好办了,把这两个数组当作两个浮点数那样编写表达式即可:
    z=np.sqrt(xs**2+ys**2)  # xs**2+ys**2是数组间的运算得到一个新数组  然后再sqrt
    z
    
        array([[7.07106781, 7.06400028, 7.05693985, ..., 7.04988652, 7.05693985,
                7.06400028],
               [7.06400028, 7.05692568, 7.04985815, ..., 7.04279774, 7.04985815,
                7.05692568],
               [7.05693985, 7.04985815, 7.04278354, ..., 7.03571603, 7.04278354,
                7.04985815],
               ...,
               [7.04988652, 7.04279774, 7.03571603, ..., 7.0286414 , 7.03571603,
                7.04279774],
               [7.05693985, 7.04985815, 7.04278354, ..., 7.03571603, 7.04278354,
                7.04985815],
               [7.06400028, 7.05692568, 7.04985815, ..., 7.04279774, 7.04985815,
                7.05692568]])
    
    # 作图
    import matplotlib.pyplot as plt
    plt.imshow(z,cmap=plt.cm.gray);plt.colorbar()
    plt.title("Image plot of $sqrt{x^2+y^2})$ for a grid of values")
    
    Text(0.5, 1.0, 'Image plot of $\sqrt{x^2+y^2})$ for a grid of values')
    

    在这里插入图片描述

    # 9.2-- numpy.where() 将条件逻辑表述为数组运算 
    
    # 9-2-1)numpy.where(conditionarr,xarr,yarr)函数
    # 三个参数都为数组,即python中三元表达式: x if condition else y 的矢量化版本。不改变 conditionarr, xarr,yarr,返回一个新的数组。
    
    # 示例:假设我们有一个布尔数组cond和两个值数组xarr,yarr:
    xarr=np.array([1.1,1.2,1.3,1.4,1.5])
    yarr=np.array([2.1,2.2,2.3,2.4,2.5])
    condarr=np.array([True,False,True,True,False])
    np.where(condarr,xarr,yarr)
    # np.where(cond,xarr,yarr).tolist()  #转化为列表
    array([1.1, 2.2, 1.3, 1.4, 2.5])
    
    # 如果使用python的列表推导式,应该是这样做:
    results=[(x if cond else y) for x,y,cond in zip(xarr,yarr,cond)]  # 得到一个列表
    results
    # 使用纯python,对于大数组效率特别慢,当xarr和yarr是多维数组时,无能为力。
    [1.1, 2.2, 1.3, 1.4, 2.5]
    
    
    # 9-2-2)当第一参数为数组判断表达式,其余参数不为数组时
    # numpy.where(condition,标量1或数组1,标量2或数组2)函数   np.where()函数的第二个和第三个参数可以不必是数组,也可以是标量或标量与数组的组合
    # 在数据分析工作中,where通常用于根据一个数组而生成另一个新数组。
    # 示例2:假设有一个随机数据组成的矩阵,你希望将所有的正值替换为2,将所有的负值替换为-2,使用where会很简单
    arrrandn=np.random.randn(4,4)
    np.where(arrrandn>0,2,-2)  # 根据一个数组而生成另一个新数组。
    array([[-2,  2,  2,  2],
           [-2,  2,  2,  2],
           [-2, -2,  2, -2],
           [-2,  2,  2, -2]])
    
    np.where(arrrandn>0,2,arrrandn)  # 只将正数用2替换,其余不变。  # 根据一个数组而生成另一个新数组。
    array([[-2.86684263,  2.        ,  2.        ,  2.        ],
          [-0.1251956 ,  2.        ,  2.        ,  2.        ],
          [-0.34407839, -0.07410133,  2.        , -0.41481679],
           [-0.73640143,  2.        ,  2.        , -0.82490141]])
    
    
    # 9-2-3)np.where(condition)
    #只有条件 (condition),没有x和y,则输出满足条件 (即非0) 元素的坐标。
    #这里的坐标以数组为元素的tuple的形式给出,通常原数组有多少维,输出的tuple中就包含几个数组,分别对应符合条件元素的各维坐标。
    a = np.array([1,3,5,7,9])
    print(np.where(a>5))     # (array([3, 4], dtype=int64),)  这是个元组
    print(a[np.where(a>5)])  # [7 9]                          得到的是列表
    
    
    
    # 9-2-4)numpy.where的嵌套使用:
    # 两个布尔类型的数组cond1和cond2,如果对应元素都是True,就是11,如果只有第一个数组的元素是True,就是10,
    # 如果只有第二个数组的元素是True,就是01,如果两个数组的对应元素都是False元,就是00,用列表接收他们。
    results=[]
    arr1=np.array([True,False,False,False,True])
    arr2=np.array([False,False,True,False,True])
    n=arr1.size
    for i in range(n):
        if arr1[i] and arr2[i]:
            results.append('11')
        elif arr1[i]:
            results.append('10')
        elif arr2[i]:
            results.append('01')
        else:
            results.append('00')
    results
    ['10', '00', '01', '00', '11']
    
    
    # 使用np.where进行嵌套就可以写得更简单:
    np.where((arr1 & arr2),'11',np.where(arr1,'10',np.where(arr2,'01','00'))).tolist()
    ['10', '00', '01', '00', '11']
    
    
    
    # 9.3,数学和统计方法  聚合函数和其他函数
    
    # 聚合函数:
    # sum       沿着轴向计算所有的累计和,0长度的数组,累计和就是0
    # mean      数学平均,0长度的数组平均值是 NAN
    # std       标准差,可以选择自由度调整(默认分母是 n)
    # var       方差,可以选择自由度调整(默认分母是 n)
    # min,max   最小值和最大值
    # argmin,argmax  最小值和最大值的位置
    
    # 其他统计方法:
    # cumsum    所有元素的累积和,第一个加数为0
    # cumprod   所有元素的累积,第一个乘数是1
    
    # 9.3.1 一些聚合函数(也叫缩减函数),比如sum,mean,std(标准差),可以作为数组的实例方法被调用,也可以作为顶级numpy函数使用,
    # 对整个数组或某个轴向的数据进行统计计算。
    # 比如: arr.mean() 和 np.mean(arr) 效果相同。
    
    # 1)示例 1  对整个数组使用聚合函数:
    
    # 准备一个正态分布的随机数组:
    arr=np.random.randn(5,4)
    # sum,mean,std的使用:
    print(arr.mean(),"--",np.mean(arr))
    print(arr.sum(),"--",np.sum(arr))
    print(arr.std(),"--",np.std(arr))
    
        0.16849962731538337 -- 0.16849962731538337
        3.3699925463076674 -- 3.3699925463076674
        0.9828447058023279 -- 0.9828447058023279
        
    
    # 1)示例 2  对数组的某个轴数据使用聚合函数:
    # sum,mean,std的使用: axis=1 可以简写为 1  1表示列轴向(列号递增的方向,其实就是行)
    print(arr.mean(axis=1),"--",np.mean(arr,axis=1))  # 计算每一列的平均值
    print(arr.sum(axis=1),"--",np.sum(arr,axis=1))    # 计算每一列的和
    print(arr.std(axis=1),"--",np.std(arr,axis=1))    # 计算每一列的标准差
    
        [ 0.39721479 -0.53907257  0.80701694  0.02321185  0.15412712] -- [ 0.39721479 -0.53907257  0.80701694  0.02321185  0.15412712]
        [ 1.58885916 -2.15629028  3.22806777  0.09284742  0.61650847] -- [ 1.58885916 -2.15629028  3.22806777  0.09284742  0.61650847]
        [0.64008158 0.66171982 0.67832542 0.677676   1.44256105] -- [0.64008158 0.66171982 0.67832542 0.677676   1.44256105]
        
    
    # sum,mean,std的使用:
    print(arr.mean(1),"--",np.mean(arr,1))  # 计算每一列的平均值   
    print(arr.sum(1),"--",np.sum(arr,1))    # 计算每一列的和
    print(arr.std(1),"--",np.std(arr,1))    # 计算每一列的标准差
    
        [ 0.39721479 -0.53907257  0.80701694  0.02321185  0.15412712] -- [ 0.39721479 -0.53907257  0.80701694  0.02321185  0.15412712]
        [ 1.58885916 -2.15629028  3.22806777  0.09284742  0.61650847] -- [ 1.58885916 -2.15629028  3.22806777  0.09284742  0.61650847]
        [0.64008158 0.66171982 0.67832542 0.677676   1.44256105] -- [0.64008158 0.66171982 0.67832542 0.677676   1.44256105]
        
    
    # sum,mean,std的使用:
    print(arr.mean(0),"--",np.mean(arr,0))  # 计算每一行的平均值
    print(arr.sum(0),"--",np.sum(arr,0))    # 计算每一行的和
    print(arr.std(0),"--",np.std(arr,0))    # 计算每一行的标准差
    
    
        [ 0.43711985  0.66037716 -0.3156837  -0.1078148 ] -- [ 0.43711985  0.66037716 -0.3156837  -0.1078148 ]
        [ 2.18559927  3.30188578 -1.57841849 -0.53907401] -- [ 2.18559927  3.30188578 -1.57841849 -0.53907401]
        [0.83383241 0.87271032 1.22192838 0.53762685] -- [0.83383241 0.87271032 1.22192838 0.53762685]
        
    
    
    # 9.3.2 其他统计函数(非聚合函数)
    # cumsum 所有元素的累计和 第一个加数是0
    # umprod 所有元素的累积 第一个乘数是1
    # 这两个函数不会使数组聚合,而是会产生一个中间结果的数组,这个数组的长度与原数组的长度一致。
    
    # 示例1--对整个数组使用cumsum,umprod:
    arr1=np.array([0,1,2,3,4,5,6,7])
    arr1.cumsum()
    array([ 0,  1,  3,  6, 10, 15, 21, 28], dtype=int32)
    
    arr1.cumprod()
    array([0, 0, 0, 0, 0, 0, 0, 0], dtype=int32)
    
    arr2=np.array([1,2,3,4,5,6,7])
    arr2.cumprod()
    array([   1,    2,    6,   24,  120,  720, 5040], dtype=int32)
    
    # 示例2--对数组的某个轴数据使用cumsum,umprod:
    arr3=np.arange(9).reshape((3,3))
    arr3
    array([[0, 1, 2],
            [3, 4, 5],
            [6, 7, 8]])
    
    arr3.cumsum(1)  # 1表示列轴向(列号递增的方向,其实就是行)
    array([[ 0,  1,  3],
           [ 3,  7, 12],
           [ 6, 13, 21]], dtype=int32)
    
    
    arr3.cumprod(1)
    array([[  0,   0,   0],
           [  3,  12,  60],
           [  6,  42, 336]], dtype=int32)
    
    
    
    # 9.4,布尔值数组的方法  
    # 同样,下面的函数既可以作为数组实例的方法被调用,也可以作为顶级numpy函数使用。
    # sum(),any(),all()
    # 这些函数也可以用于非布尔类型数组,所有非0元素,都会被认为是True.
    
    # 9.4.1 sum()函数
    arr=np.random.randn(100)
    print((arr>0).sum())  # 49   统计数组中元素大于0的个数   布尔类型数组的True相当于1,False相当于0
    print(np.sum(arr>0))  # 49
    
    # 9.4.2 any()和all(), any检查数组中是否至少有一个True,all检查数组中是否全是True
    bools=np.array([False,True,False,False])
    print(bools.any())    # True
    print(np.any(bools))  # True
    print(bools.all())    # False
    print(np.all(bools))  # False
    
    
    # 9.5,数组排序
    # 和python的内建列表类型相似,Numpy数组可以使用sort方法按位置排序:
    # arr.sort() in place sort, 会改变原数组。
    # np.sort(arr),np.sort(arr,1) 顶层的np.sort()方法返回的是数组的copy,不会改变原数组。
    # 其他排序方法:间接排序(参照高级numpy),与排序相关的其他种类的数据操作,比如根据一个表的某一列排序,(pandas会讲)
    
    # 9.5.1 arr.sort()对整个一维数组排序:
    arr=np.random.randn(6)
    arr
    array([ 0.28791664, -0.33857089, -0.25479571,  0.8856711 , -2.80537025,
                3.58768604])
    
    arr.sort()
    arr
    array([-2.80537025, -0.33857089, -0.25479571,  0.28791664,  0.8856711 ,
                3.58768604])
    
    
    # 9.5.2 arr.sort()对于二维数组排序:
    arr2=np.random.randn(5,3)
    arr2
    array([[ 1.18081678,  0.17371794,  2.37109646],
           [ 0.25508294, -1.28392   , -0.29739046],
           [ 0.65719139, -1.42167423,  0.06661373],
           [ 0.5586866 , -0.64003369,  2.32344008],
           [-0.47146893, -0.14909249, -0.42267235]])
    
    
    arr2.sort()  # 当没有参数时,实际默认参数为 1
    # arr2.sort(1) 
    arr2
    array([[ 0.17371794,  1.18081678,  2.37109646],
           [-1.28392   , -0.29739046,  0.25508294],
           [-1.42167423,  0.06661373,  0.65719139],
           [-0.64003369,  0.5586866 ,  2.32344008],
           [-0.47146893, -0.42267235, -0.14909249]])
    
    
    arr2=np.random.randn(5,3)
    arr2
    array([[-0.79484895,  0.46884083,  1.53851912],
           [ 0.62346424,  0.51440027,  0.22166369],
           [ 0.03477362, -1.9244294 ,  0.03262501],
           [-1.25440832, -0.09754629, -0.81348808],
           [-1.11063465,  0.04493534, -1.2358787 ]])
    
    
    arr2.sort(0) 
    arr2
    array([[-1.25440832, -1.9244294 , -1.2358787 ],
           [-1.11063465, -0.09754629, -0.81348808],
           [-0.79484895,  0.04493534,  0.03262501],
           [ 0.03477362,  0.46884083,  0.22166369],
           [ 0.62346424,  0.51440027,  1.53851912]])
    
    
    # 9.5.3  np.sort(arr),np.sort(arr,axis=1) ,np.sort(arr,axis=0)
    # 只拿一维数组来举例:
    arr=np.random.randn(6)
    arr
    array([-0.00642429, -0.17085358, -0.09756021, -0.26958744, -0.29145018,
               -0.8358323 ])
    
    np.sort(arr)  # 返回新的数组,不改变原数组
    array([-0.8358323 , -0.29145018, -0.26958744, -0.17085358, -0.09756021,-0.00642429])
    arr
    array([-0.00642429, -0.17085358, -0.09756021, -0.26958744, -0.29145018,-0.8358323 ])
    
    
    
    # 9.6,唯一值与其他集合逻辑   
    # Numpy 包含一些针对一维 ndarray 的基础集合操作。
    # 注,都是numpy的顶层方法,ndarray对象不存在这些方法。
    
    # np.unique(arr)                 计算arr的唯一值,并排序
    # np.intersect1d(arr1,arr2)      计算两个数组的交集,并排序
    # np.union1d(arr1,arr2)          计算两个数组的并集,并排序
    # np.ind1d(arr1,arr2)            计算arr1的元素,是否存在于arr2中
    # np.setdifferent(arr1,arr2)     差集,在arr1中,但不在arr2中的元素
    # np.setxor1d(arr1,arr2)         异或集,在arr1中或在arr2中,但不在二者的交集中
    
    # 以下只针对 np.unique(arr)   np.in1d(arr1,arr2) 进行讲解:
    
    # 9.6.1 np.unique(arr) 返回的是数组中唯一值排序(去重后排序)后形成的数组。
    names=np.array(['Bob','Joe','Will','Bob','Will','Joe','Joe'])
    np.unique(names)
    # names.unique()  这种用法不存在
    array(['Bob', 'Joe', 'Will'], dtype='<U4')
    
    ints=np.array([3,3,3,2,2,1,1,4,4])
    np.unique(ints)
    array([1, 2, 3, 4])
    
    
    # 用纯python 来实现上面的例子:
    # 使用set()函数,将数组转化为set集合,自动去重,然后用sorted()函数对set集合排序,得到列表:
    # 知识点:set(ndarray对象)得到去重后的set集合, sorted(set)得到排序后的列表。
    
    names=np.array(['Bob','Joe','Will','Bob','Will','Joe','Joe'])
    names_set=set(names)
    sorted(names_set)
    ['Bob', 'Joe', 'Will']
    
    
    ints=np.array([3,3,3,2,2,1,1,4,4])
    ints_set=set(ints)
    sorted(ints_set)
    [1, 2, 3, 4]
    
    
    #  9.6.2 np.in1d(arr1,arr2)
    # 用来检查一个数组中的值是否在另外一个数组中也出现,并返回一个和第一个数组长度一致的布尔类型数组。
    values01=np.array([5,6,7,9,0,0,3])
    values02=np.array([5,8,7,5])
    np.in1d(values01,values02)
    array([ True, False,  True, False, False, False, False])
    
  • 相关阅读:
    求第N个素数
    HDU1568
    HDU1003 DP
    POJ 1016 模拟字符串
    POJ 3321 树状数组(+dfs+重新建树)
    UVA12532 线段树(单点更新,区间求乘积的正负)
    POJ2488 dfs
    POJ 1195 二维树状数组
    HDU 4006 优先队列
    优先队列
  • 原文地址:https://www.cnblogs.com/Collin-pxy/p/13270093.html
Copyright © 2011-2022 走看看