P05-1 Read CSV#

資料來源:政府開放資料違規藥品廣告資料集

  • Get and open file

    • Get file by link then read

    • Read file on local machine

    • Mount Google Drive and read file using Colab

  • Read CSV

    • by f.read()

    • by f.readlines()

    • by csv.reader()

  • Write CSV

    • by f.write()

    • by csv.writer()

Get and Open File#

  1. 如果是在Colab或JupyterLab上,可以用wget指令將該檔案抓回來現在的資料夾中(推薦上課中這麼做)。

  2. 如果是用VSCode或jupyter撰寫,建議把csv檔下載回本機端,放到程式碼的資料夾。接下來只要弄懂資料路徑就可以讀取。https://raw.githubusercontent.com/p4css/py4css/main/data/drug_156_2.csv

  3. 如果是在colab上執行,可以先在程式中mount google drive,並把位置指到相對應的路徑。

Method 2:Jupyterlab. Read from local PC#

如果是在個人PC上,用VS Code或Jupyter等自行安裝的編輯器寫作的話,那就需要在程式碼中指定該檔案的路徑,通常以指定相對路徑為佳。相關說明如相對路徑

  1. 如果.ipynb和test.csv在同一個資料夾內,用test.csv或者./test.csv便可讀取在同一個資料夾內的檔案。

  2. 如果test.csv被放置在.ipynb所在位置的test資料夾中,用test/test.csv便可讀取,意即,在同一層中的test資料夾中的test.csv。

  3. 如果test.csv被放置在.ipynb所在位置的外部資料夾中,那就要用../test.csv往外跳出這層資料夾,每多一個..就代表往外跳一層,例如../../test.csv代表往外跳兩層

# Be sure to specify right path
with open("drug_156_2.csv", "r", encoding="utf-8-sig") as f:
    print(f)
    print(type(f))
---------------------------------------------------------------------------
FileNotFoundError                         Traceback (most recent call last)
Cell In[2], line 2
      1 # Be sure to specify right path
----> 2 with open("drug_156_2.csv", "r", encoding="utf-8-sig") as f:
      3     print(f)
      4     print(type(f))

File ~/anaconda3/lib/python3.10/site-packages/IPython/core/interactiveshell.py:282, in _modified_open(file, *args, **kwargs)
    275 if file in {0, 1, 2}:
    276     raise ValueError(
    277         f"IPython won't let you open fd={file} by default "
    278         "as it is likely to crash IPython. If you know what you are doing, "
    279         "you can use builtins' open."
    280     )
--> 282 return io_open(file, *args, **kwargs)

FileNotFoundError: [Errno 2] No such file or directory: 'drug_156_2.csv'

Method 3:Colab. Mount drive then read#

Google Colab提供一個選項是把個人的Google Drive 掛載(Mount)到Colab的執行環境中,意味著可以用程式直接讀取個人放在Google drive裡面的資料。


# Mount google drive as data
from google.colab import drive
drive.mount('/content/drive')

#data path using google colab
gdrive_path = "/content/drive/My Drive/Colab Notebooks/PSS1092/data/14196_drug_adv.csv" 

Read opened CSV#

當規劃要讀進一個CSV檔時,可以有三種做法:

  1. f.read():這個函式讀取整個檔案的內容為一個字串,需要手動使用 split('\n') 來將其切割成一行一行的資料。

  2. f.readlines():這個函式遇到換行符號 \n 會自動將檔案內容分成多個行,每一行是一個字串。然後,你可以使用 split(',') 將每一行的資料進一步切割成欄位。

  3. csv.reader():利用 csv 函式庫的 csv.reader() 函式,將文字資料轉換為 Python 物件,並自動切割成 List 中的元素。

  4. Pandas:另一個選擇是使用 Pandas 函式庫,它提供了更高級的功能來處理 CSV 檔案,後面的章節會介紹詳細內容。

當直接將已打開的檔案 f 印出時,實際上會顯示的是 f 這個變數的內容(為一個檔案物件如下列程式碼<_io.TextIOWrapper name='drug_156_2.csv' mode='r' encoding='utf-8-sig'>,而非檔案內容本身。要讀取檔案內容,我們需要使用 f.readlines()f.read() 函式。使用 f.readlines() 可以讓我們方便地讀取每一行的文字內容,而 f.read() 則會返回整個檔案的文字內容,我們可以後續自行處理。這兩者的選擇取決於我們需要處理的資料形式以及後續的處理需求。

with open("drug_156_2.csv", "r", encoding="utf-8-sig") as f:
    print(f)
    print(type(f))
<_io.TextIOWrapper name='drug_156_2.csv' mode='r' encoding='utf-8-sig'>
<class '_io.TextIOWrapper'>

Method 1: by f.read()#

當我用f.read()讀取純文字檔案內的內容時,整個內容會被轉為單一string。由於我加了Slicing f.read()[:400]來取出前400個字,剛好可以看見第一列的詮釋資料、第一二三筆資料,但到了第三筆資料的一半,便超過400個字。

with open("drug_156_2.csv", "r") as f:
    print(f.read()[:400])    
違規產品名稱,違規廠商名稱或負責人,處分機關,處分日期,處分法條,違規情節,刊播日期,刊播媒體類別,刊播媒體,查處情形
"維他肝","豐怡生化科技股份有限公司/朱O","","03 31 2022 12:00AM","","廣告內容誇大不實","02 2 2022 12:00AM","廣播電台","噶瑪蘭廣播電台股份有限公司",""
"現貨澳洲Swisse ULTIBOOST維他命D片calcium vitamin VITAMIN D400粒 補鈣 骨頭","張O雯/張O雯","","01 21 2022 12:00AM","","廣告違規","11 30 2021 12:00AM","網路","蝦皮購物","輔導結案"
"✈日本 代購 參天製藥 處方簽點眼液","蘇O涵/蘇O涵","","01 25 2022 12:00AM","","無照藥商","08 27 2021 12:00AM
all_list = []
with open('drug_156_2.csv', "r", encoding="utf-8-sig") as f:
    s = f.read()
    for line in s.split("\n"):
        row = line.split(",")
        all_list.append(row)

# s.split("\n")[0].split(",")

Method 2: by readlines()#

逐行讀取 CSV 檔案時,我們使用 readlines() 函式,它會自動判斷換行符號,將所有資料按行切割成一個清單中的元素。每一行都是一個字串,表示檔案中的一行資料。這是相對於使用 read() 函式的方式,後者讀取整個檔案內容為一個大字串,然後我們需要手動根據換行符號 \n 來切割成各行。

CSV 檔案的每一列都以換行符號 \n 作為換行,因此我們可以使用 readlines() 讀取每一行的資料。這個函式遇到換行符號 \n 時就會自動將資料分成多個行,每一行的資料都被存儲為字串。接著,我們可以遍歷這些行(例如,使用變數 line),再使用逗號 , 來切割每一行的資料,例如 line.split(","),這樣每一列的資料就變成了一個 List。最終,我們會得到一個兩層的 List,也就是 List of Lists,其中每個內部的 List 代表 CSV 檔案的一行資料。

all_list = []
with open('drug_156_2.csv', "r", encoding="utf-8-sig") as f:
    # s = f.read()
    for line in f.readlines():
    # for line in f.read().split("\n"):
        row = line.split(",")
        all_list.append(row)
# all_list[:3]
# print(type(all_list))
# print(len(all_list))
# print(all_list[:3])

# # print the first 5 lists by for-loop
# for li in all_list[:5]:
#     print(li)

# # print the length of data (the length of the outer list)
# print(len(all_list))

# # print element by index with two dimensions
# print(all_list[1][-2])

Method 3: by csv.reader()#

csv_read()並非預載於python runtime environment的基本函式,因此要import csv library,才可以使用該library中的csv_read()

Code Sample 1

import csv
with open("drug_156_2.csv", "r", encoding="utf-8-sig") as csv_file:
    csv_reader = csv.reader(csv_file, delimiter=',') # delimiter: \t , ;
    data_list  = list(csv_reader)

Code Sample 2

import csv

all_list = []
with open('drug_156_2.csv', mode='r', newline='') as file: # 讀取CSV檔案
    reader = csv.reader(file) # 建立CSV讀取器
    next(reader, None) # 跳過標題行
    for row in reader:
        all_list.append(row)
print(all_list)
# Exploring data by ...

# type(all_list)
# datall_lista_list[0]
# all_list[:3]
# print(all_list[0])
# print(all_list[1])
# print(dataall_list_list[1][-2])
# print(len(all_list))

Write CSV#

Write line by line#

但如果你有一種「寫程式的浪漫」想自己操控寫回一個文字檔案的每一行每一個字的話,可以用下面的方式寫回去。 把第二層list的每一個元素用,給黏起來,在後面再黏上一個\n

with open("output.csv", "w") as fout:
    for row in all_list:
        fout.write("%s\n" % ','.join(str(cell) for cell in row))

(Option) 字串操作的小技巧#

",".join(a-list)是一個非常好用的字串函式,可以把一個list中的每個項目用某個符號(例如前面的,)黏成字串。測試並觀察以下.join()函式的操作

Code for Practice 01

blist = [3, 2, 1]
",".join(str(b) for b in blist)

[str(b) for b in blist]

Code for Practice 02

alist = [[1, 2, 3], [4, 5, 6], [7, 8, 9], [11, 12, 13]]
",".join(str(a) for a in alist[0])
[str(cell) for cell in alist[0]]