博客 / 詳情

返回

利用 Python 進行數據分析 —— 1 數據結構、函數和文件

本文是我個人學習《利用 Python 進行數據分析》一書的筆記。整個系列於今日起連載。

1.1 數據結構

Python 的基本數據結構包括元組、列表、字典、集合,此外還有一些特殊的數據結構(如 range 對象、字符串等)。

1.1.1 元組(tuple)

什麼是元組?元組是固定長度、內容不可改變的序列。

如何創建元組?

# 用逗號分隔是創建元組最簡單的方法
tup = 1, 2, 3
tup = "a", "b", "any"
tup = (2, 3, 4), (5, 6)

# 用 tuple() 可以將一個序列轉換為元組
tup = tuple([2, 3, 4])

元組的內容是不可改變的,這句話如何理解呢?

 in: tup
out: (2, 3, 4)

 in: tup[0] = 5   # 該行命令是無法運行的,這是因為元組內的值是不能改變的

# 但是,如果元組內的某對象是可以改變的,可以在其對應位置上進行修改
 in: tup = (1, [1, 2, 3], 2)
     tup[1].append(4)  
     tup
out: (1, [1, 2, 3, 4], 2)

雖然元組的內容是不可改變的,但是元組可以串聯和拆分。

# 串聯元組
(1, 2, 4) + ('haha', [2, 3], True)   # 利用加號可以串聯元組
(1, 2) * 3   # 利用乘號可以對元組進行復制串聯

# 拆分元組
a, b, c = (1, 2, 3)
a, b, (c, d) = (1, 2, (3, 4))  # 甚至元組內的元組也會被拆分

 in: info = 'name', 'age', 'job', 'zipcode'
     a, b, *_ = info   # 可以從元組的開頭選取想要的值,其餘的值保存在 *_ 中
     print('a={}, b={}'.format(a, b))
out: a=name, b=age

元組的方法不多,常用的是 count()。

 in: num = 1, 2, 2, 2, 3, 4, 5
     num.count(2)   # count() 可以用於計數:計算元組對象中某個值出現的總次數
out: 3

1.1.2 列表(list)

與元組不同,列表的長度是可變的,內容也可以被修改。

如何創建列表?

list_fruit = ['apple', 'banana', 'orange', 'orange']
tup = 'apple', 'banana', 'orange', 'orange'
list_fruit = list(tup)   # 可以利用 list() 將其他序列轉換為列表

列表的可變性,讓我們能夠對列表進行諸多操作。

  • 向列表中添加或移除元素:
# 添加元素
list_fruit.append('pear')  # 在列表的末端添加元素
list_fruit.insert(1, 'durian')  # 在列表的特定位置添加元素
# insert 比 append 計算量大,因為插入後,後續元素的引用必須在內部遷移

# 移除元素
list_fruit.pop(1)  # 移除並返回指定位置的元素
list_fruit.remove('orange')  # 移除指定的元素(從第一個開始,一次移除一個)

# 列表的串聯
list_fruit + ['melon', 'grape']
list_fruit.extend(['durian', 'watermelon'])  # 可以利用 extend() 追加多個元素
# 加法計算量更大,因為加法創建了一個新的列表,而 extend() 是在原列表上追加元素
  • 排序
# sort() 可以將一個列表原地排序(而不創建新的對象)
 in: a = [2, 4, 6, 3, 1]
     a.sort()  
     a
out: [1, 2, 3, 4, 6]   # 默認是升序排列
 in: b = ['hah', 'kdjalkdjalk', 'd', 'ldkld']
     b.sort(key=len)   # 可以通過指定 key 參數,按元素長度排列
     b
out: ['d', 'hah', 'ldkld', 'kdjalkdjalk']

# sorted() 也可以排序,但不會改變原序列,而是創建一個新列表
 in: a = [1, 5, 7, 3, 4]
     print('sorted_a = ',sorted(a))
     print('a = ',a)
out: sorted_a =  [1, 3, 4, 5, 7]
     a =  [1, 5, 7, 3, 4]
  • 切片
 in: seq = [1, 2, 4, 6, 2, 4, 8, 9]
     seq[1:4]
out: [2, 4, 6]

 in: seq[0:2] = [100, 60]   # 可以直接對切片賦值,會改變原來的列表
     seq
out: [100, 60, 4, 6, 2, 4, 8, 9]

 in: seq[::2]  # 在第二個冒號後面使用 step,可以隔一段距離取元素
     seq[::-1]  # 這種方法可以把列表顛倒過來
out: [100, 4, 2, 8]
     [9, 8, 4, 2, 6, 4, 60, 100]

# PS: 元組也可以切片 :)
  • enumerate() 序列函數
# 在迭代時,我們常常希望知曉當前項的序號,因此我們可能會這樣寫:
i = 0
for value in list_fruit:
    print('第{}個元素是:{}'.format(i, value))
    i += 1

# 上述代碼可以被簡化:
for i, value in enumerate(list_fruit):   # 可以返回 (i, value) 樣式的元組
    print('第{}個元素是:{}'.format(i, value))
  • zip() 成對組合
# zip() 可以將多個序列成對組合成一個 zip 對象(元祖列表)
 in: seq1 = [1, 2, 3]
     seq2 = ['happy', 'sad', 'angry', 'peace']
     zipped = zip(seq1, seq2)   
     zipped
out: <zip object at 0x00000149BAC687C0>   # 這是一個迭代器,可以調用 __next__()

 in: list(zipped)   # 利用 list() 將迭代器實體化
out: [(1, 'happy'), (2, 'sad'), (3, 'angry')]   # 可以看到,zip 後元組的個數取決於最短的序列
  • reversed() 顛倒序列
 in: seq1 = [1, 2, 3]
     r = reversed(seq1)   # reversed 函數生成了一個 list_reverseiterator 對象——從後向前迭代的一個迭代器
     list(r)   # 想看到內容,還是需要使用 list() 將迭代器對象實體化
out: [3, 2, 1]

1.1.3 字典(dict)

字典的用法我記錄得較為零散,直接羅列在下面:

# 可以用 in 檢查字典中是否包含某個鍵
 in: dict_test1 = {'a': 'hahaha', 'b': [1, 3, 4],3:(12,3)}
     'a' in dict_test1
out: True

# 將鍵值移出字典
del dict_test1['b']   # del 可以刪除一對鍵值
dict_test1.pop(3)   # pop() 可以刪除一對鍵值,並返回被刪除的值

# 得到鍵列表和值列表
list(dict_test1.keys())  # 學會使用 list() 函數,可以將一些特殊序列實體化
list(dict_test1.values())
# dict_test1.keys() 得到的是一個 dict_keys 序列,它不是一個 list,不能用下標訪問
keys = dict_test1.keys()
keys[0]   # 該條命令不能運行
list(keys)[0]   # 這樣才可以  

# 字典的更新
# update 函數可以更新字典(存在的鍵,值被替換;不存在的鍵,追加新的鍵值)
 in: d = {'a':123,'b':456}
     d.update({'b': 789, 'c': '更新'})  
out: {'a': 123, 'b': 789, 'c': '更新'}

1.1.4 集合(set)

集合是一個無序的、不可重複的元素集。其概念類似於數學中的集合,可以進行合併、交集等數學運算。

# 創建集合
 in: {2, 2, 2, 1, 3, 3}
     set([2, 2, 2, 1, 3, 3])   # set() 可以把其他序列轉為集合
out: {1, 2, 3}   # 集合是不可重複的

a = {1, 2, 3, 4, 5}
b = {3, 4, 5, 6, 7, 8}
# 並集
a.union(b)
a | b
# 交集
a.intersection(b)
a & b

1.1.5 range 對象

range() 是在 for 循環中運用很頻繁的函數,我在測試代碼的時候偶然發現,range() 建立的對象既不是元組,也不是列表,而是獨特的 range 對象。

range 對象像元組一樣,其內容是不可修改的;但 range 對象不能像元組一樣存儲不同類型的內容,只能存儲一個等差數列。

range 對象、字符串、元組、列表、字典、集合,都是可迭代的對象。我們可以使用 iter() 建立一個迭代器

# 以 range 對象為例
 in: a = range(2)
     iter_test = iter(a)   # 基於可迭代的對象,創建一個迭代器
     iter_test   
out: <range_iterator object at 0x00000149BABF42D0>

 in: iter_test.__next__()   # 迭代器都有 __next__() 方法,可以返回下一個元素
out: 0

 in: iter_test.__next__()
out: 1

 in: iter_test.__next__()
out: Traceback (most recent call last):
     File "<input>", line 1, in <module>
     StopIteration   # 迭代器是一次性使用的,從頭迭代到尾,然後就不能再迭代了

for 循環的本質就是基於可迭代的對象建立一個迭代器,依次迭代到末尾。

1.1.6 列表推導式

可以用列表推導式簡化 for 循環代碼:

 in: string = ['a', 'apple', 'orange', 'banana']
     [i.upper() for i in string if len(i) > 2]
out: ['APPLE', 'ORANGE', 'BANANA']

推導式還可以嵌套:

 in: all_data = [['Eureka', 'Nirvash', 'Landon'], ['Bill', 'Steve']]
     [name for names in all_data for name in names if len(name) > 5]
out: ['Eureka', 'Nirvash', 'Landon']

1.2 函數

Python 中的函數有幾個特殊的使用方法:

# 函數可以返回多個值
def f():
    a = 5
    b = 6
    c = 7
    return a, b, c
a, b, c = f()

# Lambda 函數(匿名函數)
def short_function(x):
    return x * 2
equiv_anon = lambda x: x * 2   # 這個匿名函數和上面的常規函數有相同的作用

# 函數作為參數傳遞到另一個函數
def apply_to_list(some_list, f):   # 此處的 f 是一個函數
    return [f(x) for x in some_list]
ints = [4, 0, 1, 5, 6]
apply_to_list(ints, lambda x: x * 2)   # 此處我們把一個匿名函數作為參數傳進去了

1.3 文件操作

Python 中可以新建、打開本地文件。我更偏好下面這種方式:

with open('tmp.txt', 'a') as f:   # a:追加模式
    f.write('add some words.')
user avatar devil_5931bede13754 頭像 azonips314 頭像 u_16213461 頭像 u_16213335 頭像
4 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.