Python

Since Jan.26th,2016

1、ubuntu 下運行 python 的幾種方式

  • 在 terminal下,直接python進入交互模式,然后開始正常輸入代碼,每輸入一行就執行一行。

  • 在 terminal 下,python /home/rancho/桌面/test.py,即以默認的 python 版本執行該文件,一次性輸出結果,不再是一行一行的了。

  • 在 terminal 下,直接執行./home/rancho/桌面/helloworld.py的命令,前提是需要在【helloworld.py】這個文件中的首行先用#!開頭注明使用的解釋器。

    注:需要執行屬性。

  • 在編輯器中,如 sublime text 3,輸入后直接 ctrl+B,即在下方命令窗口中出現執行結果。

2、關于print時代碼的多行輸入

  • '''…'''用來注釋多行(本質上為一串字符串)。

  • \用來轉義\n\t等等字符,每個需要轉義的字符前都要家加\,而r則用來簡化,只要在引號前加r,引號中的就被作為原始字符串輸出。
    代碼示例如下:
    >>> print('\ttest')
    test
    >>> print('\ttest')
    \ttest
    >>> print(r'\ttest')
    \ttest
    但是,需要特別注意的是r似乎不能把引號本身作為原始字符串輸出,只能用\來實現。
    比如輸出三個單引號,用r會報錯,

    print(r''''')
    

但是用\則正常。

  print('\'\'\'')

另外,正則表達式中的一些特殊符號似乎也不能用r轉義,比如輸出.就必須用代碼\.來實現。

  • 在一個字符串中,行末的單獨一個反斜杠表示字符串在下一行繼續,而不是開始一個新的行。如下圖等價于 "This is the first sentence. This is the second sentence."

    <http://old.sebug.net/paper/python/ch04s03.html>

    注:除了字符串中,\也能起到連接多行的作用。

    <http://old.sebug.net/paper/python/ch04s08.html>

3、遞歸函數中的ifreturn

  • 遞歸函數實現的一個重要原因是函數內部調用了它本身,其實也就是return的內容還是不明確的,仍然需要調用它本身來實現的,比如一個表達式。因此一旦當return的內容確定下來,比如變成了一個常熟或是字符串,則這個函數就結束了,return后的語句不會被再次執行。
    比如
    def fact(n):
    if n == 1:
    return 1
    return n*fact(n - 1)

    print(fact(5))
    

輸出得到的是120,即5!,事實上當進行到5×4×3×2×fact(1)的時候,由于n == 1,因此return得到的不再是一個表達式,而是常數1,從而,返回的5×4×3×2×fact(1)也成為了一個確定的值,120,函數return一個確定值的目標已經的達到,也就不再進行接下來的語句,即函數調用完畢了。
但是
x=19
if x >= 17:
print(x)
print(x)
則會得到兩個19的輸出結果,因為if語句的語法中就沒有執行后跳過下面所有語句的定義,仍會執行print(x)

4、range()的用法

  • range(n)是指從0到n,但要注意的是0是被包括的,n是不被包括的,也就是0~(n-1)。

我們所做的只是提供兩個數,range返回一個序列的數。這個序列從第一個數開始到第二個數為止。例如,range(1,5)給出序列[1, 2, 3, 4]。默認地,range的步長為1。如果我們為range提供第三個數,那么它將成為步長。例如,range(1,5,2)給出[1,3]。記住,range 向上延伸到第二個數,即它不包含第二個數。
在C/C++中,如果你想要寫for (int i = 0; i < 5; i++),那么用Python,你寫成for i in range(0,5)。你會注意到,Python的for循環更加簡單、明白、不易出錯。
http://old.sebug.net/paper/python/ch06s04.html

range輸出的是有序的。

  • 另一點要注意的是,在for i in range(5)這樣的循環中并不是隱藏了i += 1這樣的語句(注意 python 中沒有i++),而是先通過range(5)生成了一個可遍歷的對象(迭代器?),而后對它進行遍歷。因此在循環內部改變i的值不影響循環進行。
    舉例代碼:
for i in xrange(5):
    print i, 
    i = 100
    print i

輸出為:

0 100
1 100
2 100
3 100
4 100

顯然,每次執行完i = 100的語句并輸出后,進行下一次循環時,i又變成了下一個數,而與100無關了。
所以,forrange的這一條組合式的語句有兩個意義:
1.提供了一個一定次數的循環。
2.為每次循環提供了一定一個按照固定規律變化的值(i)。

5、輸出時* times的用法

  • print('test' * 5)得到輸出為testtesttesttesttest

6、enumerate的用法

  • enumerate(列舉,枚舉)
# iter list with index:
  print('iter enumerate([\'A\', \'B\', \'C\']')
  for i, value in enumerate(['A', 'B', 'C']):
      print(i, value)

https://github.com/michaelliao/learn-python3/blob/master/samples/advance/do_iter.py

得到的輸出結果為

iter enumerate(['A', 'B', 'C'])
  0 A
  1 B
  2 C

因此,就可以通過這種方式把list變成索引-元素對,在迭代時同時迭代這二者。

7、isinstance的用法

  • 可以判斷一個變量是否是某些類型中的一種(例如第三條就是兩種類型)
    >>> isinstance('test', str)
    True
    >>> isinstance('313', str)
    True
    >>> isinstance(313, (int,str))
    True
    還可以用來判斷是否是可迭代對象
    from collections import Iterable
    >>> isinstance([], Iterable)
    True
    >>> isinstance({}, Iterable)
    True
    >>> isinstance('test', Iterable)
    True
    >>> isinstance((x for x in range(3)), Iterable)
    True

8、關于內置字符串處理函數

  • 內置字符串處理函數可以看成是是新生成了一個字符串,而[]所在位置不同決定了是先提取再進行函數處理還是先進行函數處理再提取。
    當然,在某些情況下兩者有相同的效果,比如下面的兩段代碼就分別自定義了一個首字母大寫,其他小寫的函數,輸出效果完全相同。
    這是第一段:
    def normalize(name):
    return name.upper()[0] + name.lower()[1:]

    L1 = ['adam', 'LISA', 'barT']
    L2 = list(map(normalize, L1))
    print(L2)
    

這是第二段:
def normalize(name):
return name.upper()[0] + name.lower()[1:]

  L1 = ['adam', 'LISA', 'barT']
  L2 = list(map(normalize, L1))
  print(L2)

輸出結果都是
['Adam', 'Lisa', 'Bart']

9、關于在dictionary中通過value查找key

  • 用迭代實現

    search_age = 19
    dict = {'george':16, 'amber': 19}
    for x, y in dict.items():
        if y == search_age:
            print(x)
    

輸出結果為

  amber

特別注意:上述的x和y都是任意更換的,完全可以換成name和age,即字典被創建的時候key和value是沒有變量來指向的,無論是x,y還是name,age都是臨時用來迭代的。

10、關于切片

  • 對于y = x[a:b:c]
    當c > 0時,a,b缺省值為0,len[x]。
    當c < 0時,a,b缺省值為-1,-len[x] - 1。因此y = x[::-1]即為x的倒序。

11、關于字符串或list相等的比較

  • 如果要比較兩個字符串或list是否相等,可以直接用==進行比較。

12、關于字符串和list的方法

  • list的方法似乎是直接作用于list本身的。
    fs = []
    fs.append('test')
    print(fs)
    輸出為
    ['test']
  • 字符串的方法似乎是創建了一個新的字符串,而非直接作用于字符串本身。
    gs = 'GGG'
    gs.lower()
    print(gs)
    輸出為
    GGG

13、關于python輸出時取消自動換行

  • 在python2中是在句末直接加,即可
    a = [1,2,3,4,5]
    for i in a:
    print i,
    得到輸出
    1 2 3 4 5
  • 在python3中是用end來控制,不光可以取消換行,還可以任意設定間隔
    a = [1,2,3,4,5]
    for i in a:
    print(i, end = ' ')
    得到輸出
    1 2 3 4 5
    又比如
    a = [1,2,3,4,5]
    for i in a:
    print(i, end = '\t')
    得到輸出
    1 2 3 4 5

14、含有0個或1個項目的元組

  • 含有0個或1個項目的tuple

一個空的元組由一對空的圓括號組成,如myempty = ()。然而,含有單個元素的元組就不那么簡單了。你必須在第一個(唯一一個)項目后跟一個逗號,這樣Python才能區分元組和表達式中一個帶圓括號的對象。即如果你想要的是一個包含項目2
的元組的時候,你應該指明singleton = (2 , )
http://old.sebug.net/paper/python/ch09s03.html

也就是說
string = (2)
print(5 - string)
這時string被認為是一個int,輸出為
3

string = (2,)
print(5 - string)
此時string才被認為是一個tuple,會報錯。

15、關于字典增加元素

  • dictionary增加元素與list不同,它沒有append方法(應當注意到dict是無序的)。
    直接為dictionary創建一個鍵/值對即可。
    she = {}
    she['lomo'] = 'test'
    print(she)
    輸出為
    {'lomo': 'test'}
    事實上,代碼和更改一個key對應的value是一樣的,不過當這個key已經存在的時候是更改,而當它不存在的時候則是創建。

16、關于file和open方法

  • python2中fileopen基本沒區別,而在python3則沒有了file的方法。
    f = open('poem.txt', 'w')
    以上代碼是可行的,直接創建了文件,而若將open換為file,則在python3中是會報錯的。

17、關于pickle模塊

  • python2中含有CPickle和pickle模塊(注意大小寫),而python3中移除了CPickle模塊。
  • python2中儲存器模塊使用中使用的是rw等,而python3中則需要用rbwb等,b表示二進制。

18、關于range和xrange

  • python3中已經取消了xrange,而python2中xrangerange共存。

19、關于decode和encode

  • decode是把其他編碼方式編碼的字符串轉換成用unicode編碼的字符串。
    str.decode('utf-8')
    上述代碼表示把utf-8編碼的字符串轉換成用unicode編碼的字符串。
  • encode則是相反,把unicode編碼的字符串轉化為其他編碼方式編碼的字符串。
    str.encode('utf-8')
    上述代碼表示把unicode編碼的字符串轉換成用utf-8編碼的字符串。
    可能在爬蟲爬取的網絡數據的寫入讀出時會用到以上兩種編碼方式。

19、關于正則表達式

  • {m,n}中,逗號,前后不可有空格(容易習慣性地在逗號后面加空格),總之,在書寫正則表達式的時候,不用考慮美觀問題的空格,怎么簡潔貼切怎么來。
  • .能匹配任意除\n以外的字符,因此.*?只適合于一行內的任意匹配,而要跨行匹配的話,應當使用[\s\S]*?\s匹配空白符,\S匹配非空白符)。
  • ^一般表示匹配字符串開頭或多行字符串的每一行開頭,但當它以這樣的形式[^...]出現時,表示取反,如[^abc]表示不是 abc 的其他字符。

20、關于文件讀寫

  • open('/home/rancho/test.txt', 'module')module可以是以下幾種

r 只能讀
r+ 可讀可寫,不會創建不存在的文件。如果直接寫文件,則從頂部開始寫,覆蓋之前此位置的內容,如果先讀后寫,則會在文件最后追加內容。
w+ 可讀可寫 如果文件存在 則覆蓋整個文件 不存在則創建
w 只能寫 覆蓋整個文件 不存在則創建
a 只能寫 從文件底部添加內容 不存在則創建
a+ 可讀可寫 從文件頂部讀取內容 從文件底部添加內容 不存在則創建
https://segmentfault.com/q/1010000003813594

  • 在打開一個文件的情況下,只要不關閉,寫入是可以進行多次的,并且是連續的,每次都是在上次的基礎上繼續寫入的。即在一個with…as…塊中,可以多次使用write方法,后面的不會覆蓋前面的。
    但是一旦關閉文件后,再次打開時,如果用的是w模式,則會全部覆蓋重寫。
  • 對于readreadlines兩個方法,都只能讀取一次,再進行讀取就會變空白。而readline則可以進行逐行讀取,雖然表面是多次讀取,實際上每短文本內容也只被讀取了一次。
  • 對于非二進制文件(純文本),使用w讀寫方式;而對于二進制文本(音樂,視頻,圖像等),要采用wb讀寫方式,不然可能會出現問題(不同的系統下可能問題不一樣)。
  • 對于w+,實際上是不能讀取到原文件內容的,因為它會先執行清空操作。也就是說你能夠讀取到的是你寫入的內容。

21 、關于urllib(urllib2)模塊

  • urllib2和urllib在python3中合并為了urllib,而在python2中主要區別在于urllib2可以接受一個Request類的對象,從而可以設置headers等。
  • response = urllib.urlopen('https://www.baidu.com/')后想要取得網頁的源代碼,需要用read方法,response.read()得到的是一個字符串,這里有兩點需要注意:
    • read方法使用后response就變為空了,也就是read方法只能用一次,而后無論是使用response還是response.read()得到的都不是剛才的數據了。
      比如說要在使用response.read()的同時測得字符串長度,則應該先foobar = response.read()把其保存在其他變量里,然后再對foobar使用len函數。
      可以通過一下以下代碼感受一下
      import urllib
      import re

      url = 'http://tieba.baidu.com/p/3138733512?see_lz=1&pn=5'
      response = urllib.urlopen(url)
      print len(response.read())
      print len(response.read())
      

輸出為
212251
0

  • read得到的網頁源代碼往往很長,會保存在內存中進行接下來的一系列操作,每對一段進行操作后最好要及時將它寫入文件,不要累加在同一個變量下多次分塊操作后最后統一寫入文件,這樣容易導致內存爆掉。

22、關于PyQt

  • 設定快捷鍵時在+前后不要留空格,即輸入一個完整的字符串。
  • 在坐標系指定位置時(一般以px為單位),從左上角開始,x 從左到右,y 從上到下。
    但碰到網格布局時,是一行一行從上往下來的,然后再是一列一列從左往右去的,比如(0,0),(0,1),(0,2),(1,0),(1,1),(1,2),(2,0),(2,1),(2,2)

23、關于中文字符編碼

  • 在 python2.x 中,加入以下代碼可以解決絕大多數問題
    # -- coding: utf-8 --
    import sys
    reload(sys)
    sys.setdefaultencoding( "utf-8" )
    • 第一行主要是解決 python 文件(源文件)對字符串的編碼。
    • 后三行主要是更改系統(指的是具體的操作系統,比如 ubuntu )默認的編碼方式,因為在 python2.x 中,encode函數無所謂直接從一種格式到另一種格式,但decode函數在轉化時需要用系統默認編碼作為中介,而默認的一般是 ascii ,不支持中文,所以即使轉換的雙方是 unicode 和 utf-8 ,都支持中文,仍然報錯。所以這三行主要是解決由于打開文件,網頁源碼獲取等等廣泛的 python 應用過程中引起的編碼格式轉化問題。
    • 以上解決絕大多數問題是指 python 解釋器不會報錯,但是仍可能碰到亂碼問題,這就需要再次用decodeencode函數進行轉化了。
    • 需要注意的是,真正的原理并不像上述文字說的那么簡單,涉及到 python2.x 中的字符串和 byte 數組類型, python 有時會自動地轉化編碼格式等等問題,因此有時可能會碰到編碼問題不在上述文字闡述理解的范圍內,但實際上都是 python2.x 在編碼上的一個設計問題(據說要考慮到兼容性),而 python3.x 似乎對這方面就有所改善,在字符串和 byte 數組類型上有改變。

24、關于錯誤處理時的 try 語句

  • try…except…是一個組合,不可拆分,即不可單獨使用try。當然在語句塊最后加finally是可以的

25、關于 Windows 和 Linux 跨平臺的問題

  • 文件路徑
    • 使用os.absname('.')查看得到的當前目錄可能是當前的 python 文件(.py)所在目錄,但也可能是編輯器或者 IDE 所在目錄。所以要選擇當前 python 文件(.py)所在目錄應當避免使用os.absname('.'),雖然在某些情況下得到的是我們想要的。

      可以使用以下幾種方式:

      • sys.argv[0]得到的是當前 python 文件(.py)的絕對路徑,若要查看目錄,則可以用os.path.dirname(sys.argv[0]),保險起見可以使用os.path.abspath(os.path.dirname(sys.argv[0])),記得先導入os即可。
      • os.path.dirname(__file__)也是可以得到當前 python 文件(.py)所在目錄的。

      跨平臺編譯時路徑的準確性尤顯重要因此,因此可以定義一個通過上述的代碼定義一個basepath作為基礎目錄,而資源文件(與 python 文件放在同一目錄下)絕對路徑可以用以下代碼實現
      basepath + os.sep + 'background.jpg'

    • 路徑前最好加上r,若在 linux 下問題不大,但在 windows 下,會出現\的轉義問題,因此最好養成習慣,只要有路徑,就使用r
      例子如下,此為 ubuntu 下代碼
      'background.jpg'
      此為 windows 下代碼
      r'C:\Users\Rancho\Desktop\background.jpg'

26、判斷變量或字符是否為整數的方法

  • 判斷變量
    一般來說用isinstance是可行的,但是不幸的是,布爾值也是int下的一個子類,因此isinstance(True, int)會得到True的輸出,故此判斷是否是整數的更合適的方法,應當是使用type(3) == int來判斷。
    注意print int, type(3), type('test')結果如下:
    <type 'int'> <type 'int'> <type 'str'>
    注意正則表達式針對的是字符串,也就是說你要是想用它來判斷必須要先將當前變量轉化為字符串,而正則表達式判斷出來也只是這個字符串所攜帶的信息是否是整數,和從根本上判斷上變量是否是整形變量還是有區別的。
  • 判斷字符
    除了使用正則表達式,也可以使用'isdigit'方法,
    test = '313'
    print test.isdigit()
    test = 'lomo'
    print test.isdigit()
    輸出為
    True
    False
    同理,對于判斷字母(注意是判斷字符是否為字母),有isalpha方法。
    但要注意的是,bool 類型的變量沒有isdigitisalpha之類的方法,若使用會報錯。

27、關于 and 和 or 以及 not 的優先順序

  • and 優先于 or
  • not 會和緊鄰的結合

28、關于刪除數組中元素的幾種方法(del,remove,pop)

  • remove是通過指定value,并且用從頭開始搜索的方式來刪除第一個符合的元素,要求輸入的變量為 value
    test = ['t', 'e', 's', 't']
    test.remove('t')
    print test
    test.remove(test[0])
    print test
    輸出為
    ['e', 's', 't']
    ['s', 't']
  • pop是通過指定索引來確定要刪除元素的位置,要求輸入的變量為 index ,同時還會返回被刪除的 value
    test = ['t', 'e', 's', 't']
    print test.pop(3)
    print test
    輸出為
    t
    ['t', 'e', 's']
  • delremove類似,也是通過指定 value 來刪除的,但因為它不是數組的方法,因此還要指定數組
    test = ['t', 'e', 's', 't']
    del test[3]
    print test
    輸出為
    ['t', 'e', 's']
    注意,
    • 不可以把del test[3]替換為del 't'
    • delremove一樣,作為通過 value 來刪除的方法,都是從頭搜索,一旦遇到符合條件的即刪除,然后結束,也就是只會刪除第一個符合條件的。因此要精確刪除的話,還是需要pop來指定索引位置的。

29、關于排列組合

  • 可以通過itertools這個庫來實現快速的排列組合,組合使用combinations函數,排列使用premutations函數。兩者都接受參數來指定挑選的元素的個數
    import itertools
    test = [1,2,3]
    print list(itertools.combinations(test, 2))
    print list(itertools.permutations(test, 2))
    輸出為
    [(1, 2), (1, 3), (2, 3)]
    [(1, 2), (1, 3), (2, 1), (2, 3), (3, 1), (3, 2)]
    注意到,itertools是個迭代器的庫,因此對于combinationspermutations兩個函數的返回結果都是迭代器,如果需要一次性輸出的需要轉化為 list 形式。

30、關于 set 和 list 的性能問題

  • 二者性能差距很大,set可能比list快上百倍以上,因此對大數據的遍歷,查找,刪除等,盡量利用set,或者將list轉為set后進行操作。

31、爬蟲中將cookie的字符串轉化為字典形式

  • pre = "utf8=?&authenticity_token=P/W5Eok1+QuvE2FgNomsDbFYBWYNWl1zv0a2K3smQjTPXeafoVXuJYnzWStGl4jzxZq8TKSbsXsFoBcL1uRo8A==&entry[field_1][]=UlT9&commit=提交"
    cookies={} 
    for line in pre.split('&'): 
    #其設置為1就會把字符串拆分成2份
        name,value=line.strip().split('=',1)
        print name,value
        cookies[name]=value
    

以上代碼將&作為連接字符,具體因情況而變。

32、scipy內模塊的導入問題

  • 大概就是說scipy是一系列模塊的集合,如果你只import scipy,那么 optimize 等這些模塊是不會自動導入的,所以你需要這樣導入,from scipy import optimize,然后就可以使用scipy.optimize了。
    https://github.com/scipy/scipy/issues/4005

33、科學計算時的浮點數和整數

  • python2 中科學計算時還是不要用from __future__ import division來用\表示精確除法代替原本的截斷除法(只取結果整數部分)了,因為這僅僅在普通表達式中起效,當用到一些第三方庫的時候,就不一定識別\為精確除法了。所以目前建議,簡單的計算的話,還是把每個數都寫成浮點數而非整數形式好了。

33、解方程

  • 一般使用sympy.solvescipy.optimize.fsolve
    https://www.zhihu.com/question/34987285
    • 因為 lambda 函數的特殊性,我現在還沒有找到 python 中方便快速的字符串轉 lambda 的方法,因此有時候scipy.optimize.fsolve還是挺不適合的。
    • 要注意sympy.solve得到的是一個數組。

34、求導數

  • 一般使用sympy.diff,接受參數是一個字符串。
    輸入:
import sympy
expression = sympy.diff('3.0*x**2.0+2.0*x')
print expression
print type(expression)

輸出:

6*x + 2
<class 'sympy.core.add.Add'>

還可以配合sympy.solve一起使用(求導數的零點):

x0 = sympy.solve(sympy.diff(expression))
print x0
[-0.333333333333333]

35、numpy 中的 mgridmeshgrid

  • meshgrid用法(用()
>>> x1 = np.arange(1, 11, 2)
>>> y1 = np.arange(-12, -3, 3)
>>> x1, y1 = np.meshgrid(x1,y1)
>>> x1
array([[1, 3, 5, 7, 9], 
         [1, 3, 5, 7, 9],
         [1, 3, 5, 7, 9]])
>>> y1
array([[-12, -12, -12, -12, -12],
         [ -9, -9, -9, -9, -9],
         [ -6, -6, -6, -6, -6]])
  • mgrid用法(用[]
>>> x2, y2 = np.mgrid[1:11:2, -12:-3:3]
>>> x2
array([[1, 1, 1],
        [3, 3, 3],
        [5, 5, 5],
        [7, 7, 7],
        [9, 9, 9]])
>>> y2
array([[-12, -9, -6],
        [-12, -9, -6],
        [-12, -9, -6],
        [-12, -9, -6],
        [-12, -9, -6]])

另一種用法是不提供步長參數,但提供數量參數

xs,ys = np.mgrid[-4:1:30j,0.8:1.1:30j] 

其中的30j表示的是從 start 到 end 的總個數,如果兩個不一致,會取大的那個。保證兩者個數一致。

36、matplotlib 畫圖

  • 2D 折線圖或散點圖
import matplotlib.pyplot as plt
plt.figure()
ax = plg.gca()
ax.set_aspect(1) # 使橫縱坐標軸對單位區間的實際長度(axes per unit length)相等
plt.plot(x,y,'rx-',linewidth=2,markersize=5,label='test')
plt.xlim([-1,1])
plt.title()
plt.xlabel()
plt.ylabel()
plt.legend()
plt.show()
  • 3D 折線圖
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure()
ax = fig.add_subplot(111,projection='3d')
ax.plot(xs,ys,'rx-',zs=zs,linewidth=2,markersize=5,label='test')
ax.set_zlim([-1,1])
plt.title()
ax.set_title()
ax.set_xlabel()
ax.set_ylabel()
ax.legend()
plt.show()
  • 3D 曲面圖
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

  k,b=np.mgrid[1:3:3j,4:6:3j]
  f_kb=3*k+2*b+1

  fig = plt.figure()
  ax = fig.add_subplot(111,projection='3d')
  ax.plot_surface(k,b,f_kb)
  plt.show()

在畫 3D 圖前,我們一般用mgridmeshgrid來生成需要 x,y軸上的變量矩陣。畫 3D 圖的要求是 z 矩陣的行數等于 x 矩陣的行數列數等于 y 矩陣的列數。也就是由如下的對應關系(以 3 階矩陣為例):

y1,1 y1,2 y1,3
x1,1 z1,1 z1,2 z1,3
x2,1 z2,1 z2,2 z2,3
x3,1 z3,1 z3,2 z3,3

mgrid為例,我們看mgrid生成的矩陣可以發現,x 的每一行都是一樣的,而 y 的每一列都是一樣的,這其實是為了代入 z 的函數進行計算比較方便,比如 z 就可以直接生成z = 2*x + 3*y,正好是一一對應的。
colorbar:注意,如果要顯示 colorbar,需要在 plot_surface 時先指定映射

from matplotlib import cm
 ax.plot_surface(k,b,f_kb,cmap=cm.coolwarm)
fig.colorbar(surf, shrink=0.5, aspect=5)
ax.legend()
  • 等高線圖(2D 和 3D)
    2D 代碼:
k,b=np.mgrid[1:3:3j,4:6:3j]
f_kb=3*k+2*b+1

  fig = plt.figure()
  ax = fig.add_subplot(111)
  ax.contour(k,b,f_kb,np.logspace(-2, 2, 70))
  plt.show()

在處理數據時和 3D 曲面圖是一樣的,都是用到了mgridmeshgrid函數,而上述代碼中contour的第四個參數是指 z 軸取 0.01 到 100 之間,并劃分成70個平面,即有 70 條等高線充滿這個范圍(但實際顯示可能不到70條,因為還要看 x 軸和 y 軸的范圍限制)。

如果我只想畫出 z=1,z=2,z=3 這 3 條等高線呢?
plt.contour(X, Y, Z,[1,2,3])

要注意的是contour(X, Y, Z,1)的意思是只畫一條等高線出來,至于是哪一條,就不知道了,而contour(X, Y, Z,[1])的意思是畫出 z=1 的這一條等高線。
http://blog.csdn.net/william_2015/article/details/47304687

如果需要對等高線加上圖例,不能直接通過ax.contour(xc,yc,zc,label='text')實現,而需要單獨設置,比如:

CS = ax.contour(xc,yc,zc)
CS.collections[0].set_label('text')
ax.legend()

同樣地,設置 linewidth 等屬性也類似,使用CS.collections[0].set_linewidth(2)等語句來實現。
其實,等高線圖可以直接在圖上標出每條線代表的值,而不需要通過圖例。具體代碼如下:

CS = ax.contour(xc,yc,zc)
ax.clabel(CS)

因為這不是圖例,所以不需要legend方法即可顯示。
最后,如果要畫 3D 的等高線圖,只要將

ax = fig.add_subplot(111)

改為

ax = fig.add_subplot(111,projection='3d')

即可。

  • 在同一個 figure 中同時畫 2D 和 3D
fig = plt.figure()
ax1 = fig.add_subplot(211)
ax2 = fig.add_subplot(212,projection='3d')
plt.show()
  • 3D 圖中坐標軸的隱藏,背景顏色的設置等
color_bg = (0.1843,0.3098,0.3098)
color_green = 'g'
color_yellow = '#f06215'
color_white = '#ffffff'
color_red = 'r'
fig = plt.figure(facecolor=color_bg) # 設置外圍顏色
fig.suptitle('3D Realtime Re-modeling',color=color_white) # 設置主標題顏色
ax = fig.add_subplot(111,projection='3d',axisbg=(0.1843,0.3098,0.3098)) # 設置畫圖區域背景顏色
ax.w_xaxis.set_pane_color(color_bg) # 設置坐標平面顏色
ax.w_zaxis.line.set_lw(0.) # 設置 z 軸線寬(類似語句對 x,y無效)
ax.tick_params(axis='x', colors=color_white) # 設置坐標軸刻度顏色
ax.set_xlabel('x',color=color_red) # 設置坐標軸標簽顏色
ax.set_xlim([1,6]) # 設置坐標軸范圍
ax.set_yticks(np.linspace(1,4,4)) # 設置坐標軸刻度
ax.set_zticks([]) # 設置坐標軸無刻度
plt.gca().invert_yaxis() # 翻轉坐標軸

如果要設置網格線參數,需要在實例化 figure 之前設置如下代碼:

from matplotlib import rcParams
rcParams['grid.linestyle'] = '-'
rcParams['grid.color'] = 'g'
rcParams['grid.linewidth'] = 0.5

如果要隱藏所有坐標軸:

ax._axis3don = False
  • 動態畫圖(實時更新)
    正常情況下plt.show()會阻塞線程,因此需要plt.ion(),這樣的話plt.show()就不會阻塞線程,程序可以繼續運行。但是圖像仍然不會更新,需要使用循環plt.pause(0.05),在這 0.05s 的時間內更新圖像并支持鼠標移動,因為是循環,所以感覺不到明顯的阻塞。如果 pause 時間過長的話,那么這段時間內新的數據就會無法繪制圖像,會導致圖像繪制的延遲。
  • 設置坐標軸
    注意ax.set_yticks或者plt.yticks都要在plot后執行才能生效。
  • 設置 subplot 之間的間距
plt.subplot(121)
plt.plot(x_list, y_list)
plt.subplots_adjust(wspace = 0.05, hspace=0.05)

關于 subplots_adjust 的參數說明:

subplots_adjust(left=None, bottom=None, right=None, top=None,
                wspace=None, hspace=None)
left  = 0.125  # the left side of the subplots of the figure
right = 0.9    # the right side of the subplots of the figure
bottom = 0.1   # the bottom of the subplots of the figure
top = 0.9      # the top of the subplots of the figure
wspace = 0.2   # the amount of width reserved for blank space between subplots,
               # expressed as a fraction of the average axis width
hspace = 0.2   # the amount of height reserved for white space between subplots,
               # expressed as a fraction of the average axis height
  • 消除保存的圖片兩側的空白
    在 jupyter 中看圖片兩側可能沒有空白,但保存下來的圖片會顯示有空白,消除空白的方法是在保存時加上bbox_inches='tight'
fig = plt.figure()
fig.savefig('test.png', bbox_inches='tight')
  • 保存高質量的圖片
    使用 svg 格式(可能會很大,可以和 raw 格式匹敵)或者高 dpi 的 png 格式
fig = plt.figure()
fig.savefig('test.png', dpi=600)
fig = plt.figure()
fig.savefig('test.svg')

37、numpy 中為矩陣添加一行(列)和在同一行(列)中添加元素

  • numpy.c_
>>> a = np.array([[1,2,3],[4,5,6],[7,8,9]])
>>> b = np.ones(3)
>>> np.c_[a,b]
array([[ 1.,  2.,  3.,  1.],
         [ 4.,  5.,  6.,  1.],
         [ 7.,  8.,  9.,  1.]])

其實有好幾種實現函數,見http://www.tuicool.com/articles/ZVrUjq3

  • numpy.append
>>> np.append([1, 2, 3], [[4, 5, 6], [7, 8, 9]])
array([1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> np.append(np.array([1,2,3]),[4,5,6])
array([1, 2, 3, 4, 5, 6])

38、numpy 中 array 的復制

  • 不能直接使用 =或切片([:]),應該使用顯式復制,即copy
import numpy as np
a = np.array([[1,2,3]])
b = np.copy()

這一點和 list 不同,對于 list,=不會復制數據,而切片可以。對于 numpy 中的 array,=和切片都不會復制數據,需要copy才可以。
參考http://blog.csdn.net/xidianliutingting/article/details/51682867

39、numpy 中 array 和 matrix 對一維的處理

  • array 把一維看成列向量,而 matrix 則看成以行數為 1 的矩陣(行向量

    In [1]: np.array([1,1,1]).shape
    Out[1]: (3,)
    In [2]: np.matrix([1,1,1]).shape
    Out[2]: (1, 3)
    

40、pandas 基本操作

  • 按標簽取出一行(得到series):df.ix['lable'](比如在使用 describe之后)

    # df is a dataframe
    
  • 求標準差:pandas 求標準差是樣本標準差(N-1),numpy 求標準差是總體標準差(N)。因此需要求樣本標準差(無偏)時,

    df.std()
    

    需要求總體標準差時,需要用values轉成 numpy 的 array 計算,

    df.values.std()
    

41、超長字符串的聲明

  • 特殊格式

    long_string = (
        'Lorem ipsum dolor sit amet, consectetur adipisicing elit, '
        'sed do eiusmod tempor incididunt ut labore et dolore magna '
        'aliqua. Ut enim ad minim veniam, quis nostrud exercitation '
        'ullamco laboris nisi ut aliquip ex ea commodo consequat. '
        'Duis aute irure dolor in reprehenderit in voluptate velit '
        'esse cillum dolore eu fugiat nulla pariatur. Excepteur sint '
        'occaecat cupidatat non proident, sunt in culpa qui officia '
        'deserunt mollit anim id est laborum.'
    )
    

    參考http://stackoverflow.com/questions/8577027/how-to-declare-a-long-string-in-python

42、缺失值(NAN)

  • 缺失值不能用==判斷

    In [11]: None == None
    Out[11]: True
    In [12]: np.nan == np.nan
    Out[12]: False
    
  • 可以使用pandas.isnull()來判斷單個數據是否是NAN

43、字典 key 搜索

44、requests 庫

  • 消除 SSL warning
import requests.packages.urllib3
requests.packages.urllib3.disable_warnings()
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容