Thông báo: Download 4 khóa học Python từ cơ bản đến nâng cao tại đây.
Xử lý văn bản trong Pandas
Trong bài này mình sẽ hướng dẫn cách làm việc với văn bản trong Pandas, đây là một kiểu dữ liệu rất phổ biến trong Python nói chung và Pandas nói riêng.
Trong những bài trước, hầu như mình chỉ sử dụng dữ liệu số để ví dụ cho các bài học về Pandas. Tuy nhiên trong thực tế thì bên cạnh dữ liệu số chắc chắn sẽ luôn có dữ liệu văn bản. Trong bài hôm nay chúng ta sẽ cùng tìm hiểu cách thao tác với dữ liệu văn bản trong Pandas nhé.
1. Kiểu dữ liệu văn bản trong Pandas
Giới thiệu về kiểu dữ liệu string
Trong Pandas, ta có thể tạo một Series từ chuỗi đơn giản như sau:
import pandas as pd import numpy as np f = pd.Series(['Freetuts', 'Học lập trình online']) print(f)
0 Freetuts 1 Học lập trình online dtype: object
Ta có thể thấy dtype của Series này được Pandas chỉ định là object, đây chính là kiểu dữ liệu mặc định khi nhận một danh sách mà trong nó tồn tại giá trị không phải là số.
Bài viết này được đăng tại [free tuts .net]
Trước Pandas phiên bản 1.0, khi lưu trữ văn bản trong DataFrame hay Series thì dtype duy nhất mà Pandas cung cấp đó là object. Điều này sẽ gây ra một số bất lợi sau:
- Dễ lưu trữ lẫn lộn giữa dữ liệu văn bản và các kiểu dữ liệu khác (do object là kiểu dữ liệu chung nên bất kỳ loại dữ liệu nào cũng có thể là object).
- Vì là kiểu dữ liệu chung chung cho nên rất khó để cụ thể hoá một số phương thức riêng cho kiểu dữ liệu văn bản. Bạn không thể thêm những phương thức liên quan đến văn bản như cắt, in hoa, in thường,... vào object được do nếu sử dụng lên dữ liệu số sẽ gây xung đột.
Từ sau phiên bản 1.0, Pandas đã bổ sung một kiểu dữ liệu dành riêng cho văn bản là StringDtype. Chúng ta có thể chỉ định cho Series trên thành kiểu này bằng 3 cách:
print("Cách 1: \n", pd.Series(['Freetuts', 'Học lập trình online'], dtype=pd.StringDtype())) print("\nCách 2: \n", pd.Series(['Freetuts', 'Học lập trình online'], dtype='string')) print("\nCách 3: \n", pd.Series(['Freetuts', 'Học lập trình online']).astype('string'))
Cách 1: 0 Freetuts 1 Học lập trình online dtype: string Cách 2: 0 Freetuts 1 Học lập trình online dtype: string Cách 3: 0 Freetuts 1 Học lập trình online dtype: string
Nếu như bạn áp kiểu string lên danh sách trong đó có các phần tử không phải là văn bản thì chúng sẽ được ép sang chuỗi, chẳng hạn:
f_v = pd.Series(['Freetuts', 99, np.nan, 'Học lập trình', 'online', True], dtype='string') print("series: \n", f_v) print("\nGiá trị của phần tử số 1: ", f_v[1]) print("Kiểu dữ liệu của phần tử số 1: ", type(f_v[1])) print("\nGiá trị của phần tử số 5:", f_v[5]) print("Kiểu dữ liệu của phần tử số 5:", type(f_v[5]))
series: 0 Freetuts 1 99 2 <NA> 3 Học lập trình 4 online 5 True dtype: string Giá trị của phần tử số 1: 99 Kiểu dữ liệu của phần tử số 1: <class 'str'> Giá trị của phần tử số 5: True Kiểu dữ liệu của phần tử số 5: <class 'str'>
Sự khác biệt giữa kiểu string và object
Tất nhiên với việc xuất hiện kiểu dữ liệu riêng dành cho chuỗi và văn bản, mình luôn khuyến khích các bạn sử dụng dtype này để lưu dữ liệu dạng văn bản vì nó sẽ trực quan hơn so với việc dùng object.
Có một số sự khác biệt đáng chú ý giữa kiểu object và string mà bạn cần biết, đầu tiên đó là nếu như không xuất hiện NA trong dãy (giá trị null) thì một số phương thức áp dụng cho cả 2 kiểu (sẽ nói cụ thể bên dưới) sẽ cùng trả về dtype là int64, giả sử ta sẽ đếm xem trong dãy có các phần tử nào chứa ký tự 'e' hay không:
s = pd.Series(['f', 'r', 'e', 'e', 't', 'u', 't', 's'], dtype='string') o = pd.Series(['f', 'r', 'e', 'e', 't', 'u', 't', 's'], dtype='object') print("Phần tử mang giá trị = 'e' (dtype='string'): \n", s.str.count('e')) print("\nPhần tử mang giá trị = 'e' (dtype='object'): \n", o.str.count('e'))
Phần tử mang giá trị = 'e' (dtype='string'): 0 0 1 0 2 1 3 1 4 0 5 0 6 0 7 0 dtype: Int64 Phần tử mang giá trị = 'e' (dtype='object'): 0 0 1 0 2 1 3 1 4 0 5 0 6 0 7 0 dtype: int64
Sự khác biệt sẽ xuất hiện khi trong dãy có chứa NA hoặc là một giá trị khác chuỗi (số, boolean,...), khi đó dtype object sẽ trả về float64 còn string vẫn sẽ là int64:
s = pd.Series(['f', 'r', 'e', 'e', 100, 't', 'u', 't', 's', None], dtype='string') o = pd.Series(['f', 'r', 'e', 'e', 100, 't', 'u', 't', 's', None], dtype='object') print("Phần tử mang giá trị = 'e' (dtype='string'): \n", s.str.count('e')) print("\nPhần tử mang giá trị = 'e' (dtype='object'): \n", o.str.count('e'))
Phần tử mang giá trị = 'e' (dtype='string'): 0 0 1 0 2 1 3 1 4 0 5 0 6 0 7 0 8 0 9 <NA> dtype: Int64 Phần tử mang giá trị = 'e' (dtype='object'): 0 0.0 1 0.0 2 1.0 3 1.0 4 NaN 5 0.0 6 0.0 7 0.0 8 0.0 9 NaN dtype: float64
Bên cạnh việc trả về kiểu dữ liệu khác, một điều mà ta để ý đó là phần tử số nguyên (giá trị 100) ở Series có dtype string trả về giá trị 0 (do '100' không chứa 'e'), còn với dtype là object thì sẽ trả về là NA. Lý do đơn giản là vì với dtype string thì phần tử này đã được chuyển thành chuỗi, còn phần tử kia vẫn mang giá trị là số nguyên:
print("Phần tử: ", s[4], " có kiểu dữ liệu là: ", type(s[4])) print("Phần tử: ", o[4], " có kiểu dữ liệu là: ", type(o[4]))
Phần tử: 100 có kiểu dữ liệu là: <class 'str'> Phần tử: 100 có kiểu dữ liệu là: <class 'int'>
Đây là một điểm mà các bạn nên chú ý để tránh nhầm lẫn khi sử dụng dtype string so với object truyền thống.
2. Các phương thức trên kiểu dữ liệu văn bản trong Pandas
Danh sách các phương thức trong Pandas
Để truy cập các phương thức thao tác với dữ liệu văn bản trong Pandas thì ta sẽ truy cập qua thuộc tính str như sau:
s = pd.Series(['Freetuts', np.nan, 'net', 'NumPy', 'Javascript', 'Học lập trình online', True, 1, 'a'], dtype='string') print("Series: \n", s) print("\nĐộ dài của các phần tử:\n", s.str.len()) print("\nIn hoa tất cả phần tử:\n", s.str.upper()) print("\nIn thường tất cả phần tử:\n", s.str.lower())
Series: 0 Freetuts 1 <NA> 2 net 3 NumPy 4 Javascript 5 Học lập trình online 6 True 7 1 8 a dtype: string Độ dài của các phần tử: 0 8 1 <NA> 2 3 3 5 4 10 5 20 6 4 7 1 8 1 dtype: Int64 In hoa tất cả phần tử: 0 FREETUTS 1 <NA> 2 NET 3 NUMPY 4 JAVASCRIPT 5 HỌC LẬP TRÌNH ONLINE 6 TRUE 7 1 8 A dtype: string In thường tất cả phần tử: 0 freetuts 1 <NA> 2 net 3 numpy 4 javascript 5 học lập trình online 6 true 7 1 8 a dtype: string
Dưới đây là bảng tất cả các phương thức trên chuỗi được hỗ trợ trong Pandas:
Phương thức | Mô tả |
lower() | Chuyển đổi các chuỗi trong Series/Index thành chữ in thường |
upper() | Chuyển đổi các chuỗi trong Series/Index thành chữ in hoa |
len() | Tính độ dài chuỗi |
strip() | Loại bỏ khoảng trắng (whitespace) của chuỗi trong Series/Index |
split(pattern) | Tách chuỗi với tham số pattern (mẫu) truyền vào |
cat(sep=' ') | Nối các phần tử trong Series/Index với dấu ngăn cách là tham số sep |
get_dummies() | Trả về DataFrame |
contains(pattern) | Trả về True nếu phần tử chứa pattern và ngược lại |
replace(a,b) | Thay giá trị a bằng b trong từng phần tử |
repeat(value) | Lặp lại từng phần tử với số lần xác định |
count(pattern) | Trả về số lần xuất hiện của pattern trong mỗi phần tử |
startswith(pattern) | Trả về True nếu phần tử bắt đầu bằng pattern và ngược lại |
endswith(pattern) | Trả về True nếu phần tử kết thúc bằng pattern và ngược lại |
find(pattern) | Trả về vị trí đầu tiên của lần xuất hiện pattern đầu tiên trong từng phần tử |
findall(pattern) | Trả về danh sách tất cả các lần xuất hiện của pattern |
swapcase() | Hoán đổi chữ hoa / chữ thường |
islower() | Trả về True nếu các phần tử đều là chữ thường và ngược lại |
isupper() | Trả về True nếu các phần tử đều là chữ hoa và ngược lại |
isnumeric() | Trả về True nếu phần tử là số và ngược lại |
Các phương thức split, replace và concat là những phương thức khá quan trọng và có một vài tham số riêng, do đó mình sẽ nói kỹ ở các mục dưới, còn ở đây chúng ta sẽ đến một số ví dụ với các hàm còn lại:
s = pd.Series(['Freetuts', np.nan, 'net', 'lập trình', 100, 'Học lập trình online', 69, True], dtype='string') print("Tìm từ 'lập trình' trong các phần tử: \n", s.str.find('lập trình')) print("\nTìm ký tự 't' trong các phần tử: \n", s.str.findall('t')) print("\nNhững phần tử là số: \n", s.str.isnumeric()) print("\nLặp lại phần tử 2 lần: \n", s.str.repeat(2)) print("\nHoán đổi chữ hoa / thường: \n", s.str.swapcase())
Tìm từ 'lập trình' trong các phần tử: 0 -1 1 <NA> 2 -1 3 0 4 -1 5 4 6 -1 7 -1 dtype: Int64 Tìm ký tự 't' trong các phần tử: 0 [t, t] 1 <NA> 2 [t] 3 [t] 4 [] 5 [t] 6 [] 7 [] dtype: object Những phần tử là số: 0 False 1 <NA> 2 False 3 False 4 True 5 False 6 True 7 False dtype: boolean Lặp lại phần tử 2 lần: 0 FreetutsFreetuts 1 <NA> 2 netnet 3 lập trìnhlập trình 4 100100 5 Học lập trình onlineHọc lập trình online 6 6969 7 TrueTrue dtype: string Hoán đổi chữ hoa / thường: 0 fREETUTS 1 <NA> 2 NET 3 LẬP TRÌNH 4 100 5 hỌC LẬP TRÌNH ONLINE 6 69 7 tRUE dtype: string
Với phương thức get_dummies thì mục đích chính của phương thức này là trích xuất các biến giả (dummy variables) từ Series hoặc Index:
s = pd.Series(["Freetuts", "Freeuts|net", np.nan, "Freetuts|org"], dtype="string") print("Series: \n", s.str.get_dummies(sep='|')) idx = pd.Index(["Freetuts", "Freeuts.net", np.nan, "Freetuts.org"], dtype="string") print("\nIndex: \n", idx.str.get_dummies(sep='.'))
Series: Freetuts Freeuts net org 0 1 0 0 0 1 0 1 1 0 2 0 0 0 0 3 1 0 0 1 Index: MultiIndex([(1, 0, 0, 0), (0, 1, 1, 0), (0, 0, 0, 0), (1, 0, 0, 1)], names=['Freetuts', 'Freeuts', 'net', 'org'])
Ta có thể dùng phương thức này để tìm sự xuất hiện của các phần tử duy nhất ở từng vị trí trong dãy, ví dụ:
f = pd.Series(['Freetuts', np.nan, 'net', 100, 'Freetuts', 'Học lập trình online', True, 'Freetuts'], dtype='string') f.str.get_dummies()
100 Freetuts Học lập trình online True net # Tên các cột là giá trị các phần tử được sắp xếp theo thứ tự và là duy nhất 0 0 1 0 0 0 # Phần tử 'Freetuts' xuất hiện tại vị trí đầu tiên 1 0 0 0 0 0 # Không có phần tử nào tương ứng xuất hiện tại vị trí 1 do vị trí này chứa NA 2 0 0 0 0 1 # ... 3 1 0 0 0 0 # ... 4 0 1 0 0 0 # Phần tử 'Freetuts' xuất hiện tại vị trí 4 5 0 0 1 0 0 # ... 6 0 0 0 1 0 # ... 7 0 1 0 0 0 # Phần tử 'Freetuts' xuất hiện tại vị trí 7
Ngoài việc áp dụng với Series, ta có thể sử dụng các phương thức trên với Index trong DataFrame:
df = pd.DataFrame({'Category': ['NumPy', 'Matplotlib', 'Pandas'],'Views': [10000, 20000, 30000]}) print("DataFrame: \n", df) df['Category'] = df['Category'].str.upper() df.columns = df.columns.str.lower() print("\nChuyển cột category thành in hoa và tên các cột thành in thường: \n", df)
DataFrame: Category Views 0 NumPy 10000 1 Matplotlib 20000 2 Pandas 30000 Chuyển cột category thành in hoa và tên các cột thành in thường: category views 0 NUMPY 10000 1 MATPLOTLIB 20000 2 PANDAS 30000
Indexing và Extracting
Indexing
Bạn có thể dùng ký hiệu [] để index trực tiếp vào chuỗi thông qua thuộc tính str, nếu như index ra bên ngoài chuỗi thì giá trị trả về sẽ là NA:
s = pd.Series(['Freetuts', 'a', 'A', 'Lập trình', None], dtype='string') print('Index vào ký tự đầu tiên của các phần tử: \n', s.str[0]) print('\nIndex vào ký tự thứ 3 của các phần tử: \n', s.str[2])
Index vào ký tự đầu tiên của các phần tử: 0 F 1 a 2 A 3 L 4 <NA> dtype: string Index vào ký tự thứ 3 của các phần tử: 0 e 1 <NA> 2 <NA> 3 p 4 <NA> dtype: string
Extracting
Để extracting (trích xuất) các chuỗi con trong từng phần tử thì Pandas cung cấp cho ta 2 phương thức sau:
- extract: trích xuất giá trị khớp đầu tiên
- extractall: trích xuất tất cả các giá trị khớp
Các phương thức trên đều chấp nhận regex làm tham số. Ta sẽ thử một ví dụ sau:
s = pd.Series(['x1', 'z2', 'y2', 'f3'], dtype='string') # Regex bên dưới khớp những phần tử có chứa ký tự x,y hoặc z và những số đi kèm phía sau print(s.str.extract(r"([xyz])(\d)", expand=False))
0 1 0 x 1 1 z 2 2 y 2 3 <NA> <NA> # Phần tử cuối cùng (f3) không khớp với regex nên giá trị trả về là NA
Lưy ý rằng phương thức extract nhận tham số expand mặc định là True, với True thì kết quả trả về luôn là DataFrame, còn False thì kết quả trả về có thể là Index, Series hoặc DataFrame tuỳ thuộc vào dữ liệu và regex mà ta chỉ định:
s = pd.Series(['x1', 'z2', 'y2', 'f3'], dtype='string') print("Trả về DataFrame: \n", s.str.extract(r"([xyz])", expand=True)) print("\nTrả về Series: \n", s.str.extract(r"([xyz])", expand=False))
Trả về DataFrame: 0 0 x 1 z 2 y 3 <NA> Trả về Series: 0 x 1 z 2 y 3 <NA> dtype: string
Chúng ta còn có thể đặt tên của cột khi trích xuất như sau:
s = pd.Series(['x1', 'z2', 'y2', 'f3'], dtype='string') print(s.str.extract(r"(?P<chữ>[xyz])(?P<số>\d)", expand=False))
chữ số 0 x 1 1 z 2 2 y 2 3 <NA> <NA>
Khác với extract, phương thức extractall luôn luôn trả về là DataFrame và sẽ có một cột index tên là "match" chứa thứ tự xuất hiện tương ứng với regex:
s = pd.Series(['x1x2x3', 'y1y2', 'z1', 'a1', 'c1c2'], index=['X', 'Y', 'Z', 'A', 'C'], dtype='string') rg = "(?P<chữ>[a-z])(?P<số>[0-9])" print("Extract: \n", s.str.extract(rg)) print("\nExtract all: \n", s.str.extractall(rg))
Extract: chữ số X x 1 Y y 1 Z z 1 A a 1 C c 1 Extract all: chữ số match X 0 x 1 1 x 2 2 x 3 Y 0 y 1 1 y 2 Z 0 z 1 A 0 a 1 C 0 c 1 1 c 2
Tách (spliting)
Để tách từng phần tử trong Series/Index theo pattern nhất định ta dùng phương thức split:
s = pd.Series(['free_tuts', 'lap_trinh', np.pi, 'pandas', None], dtype='string') print(s.str.split('_'))
0 [free, tuts] 1 [lap, trinh] 2 [3.141592653589793] 3 [pandas] 4 <NA> dtype: object
Ta có thể lấy từng phần tử đã được tách ra bằng phương thức get hoặc index như trên:
print(s.str.split('_').str.get(0)) print(s.str.split('_').str[0])
0 free 1 lap 2 3.141592653589793 3 pandas 4 <NA> dtype: object 0 free 1 lap 2 3.141592653589793 3 pandas 4 <NA> dtype: object
Ta có thể truyền tham số expand=True để trả về một DataFrame chứa từng phần tử đã được tách thay vì một mảng:
print(s.str.split('_', expand=True))
0 1 0 free tuts 1 lap trinh 2 3.141592653589793 <NA> 3 pandas <NA> 4 <NA> <NA>
Phức tạp hơn, chúng ta có thể giới hạn số lần chia bằng tham số n:
s = pd.Series(['free_tuts_net', 'lap_trinh_python', np.pi, 'python_pandas', None], dtype='string') print(s.str.split('_', expand=True, n=1))
0 1 0 free tuts_net 1 lap trinh_python 2 3.141592653589793 <NA> 3 python pandas 4 <NA> <NA>
Pandas còn hỗ trợ thêm phương thức rsplit, phương thức này giống như split nhưng hoạt động ở chiều ngược lại (reverse):
s = pd.Series(['free_tuts_net', 'lap_trinh_python', np.pi, 'python_pandas', None], dtype='string') print(s.str.rsplit('_', expand=True, n=1))
0 1 0 free_tuts net 1 lap_trinh python 2 3.141592653589793 <NA> 3 python pandas 4 <NA> <NA>
Thay thế (replacing)
Ta sử dụng phương thức replace để thay thế tường phần tử theo tham số truyền vào, tham số có thể là chuỗi thông thường cho tác vụ đơn giản hoặc là regex cho những thứ phức tạp hơn:
s = pd.Series(['Free_Tuts_net', 'lap_trinh_python', np.pi, 'python_pandas', None], dtype='string') print(s.str.replace('e|^python', '.', regex=True))
0 Fr.._Tuts_n.t 1 lap_trinh_python 2 3.141592653589793 3 ._pandas 4 <NA> dtype: string
Nối (concatenate)
Nối Series thành một chuỗi
Chúng ta dùng phương thức cat để nối các phần tử trong chuỗi, chúng ta có thể truyền tham số sep để chỉ định chuỗi ngăn cách khi nối, còn không thì mặc định sẽ là chuỗi rỗng (''):
s = pd.Series(['f','r','e','e','t','u','t','s'], dtype='string') print("Không truyền sep: ", s.str.cat()) print("sep='|': ", s.str.cat(sep='|'))
Không truyền sep: freetuts sep='|': f|r|e|e|t|u|t|s
Nối một list với Series
Chúng ta có thể truyền vào tham số đầu tiên là một List bất kỳ (chiều dài phải tương đương Series), khi đó Series và List sẽ được ghép với nhau theo vị trí tương ứng:
s = pd.Series(['f','r','e','e','t','u','t','s'], dtype='string') d = ['F', 'R', 'E', 'E', 'T', 'U', 'T', 'S'] print(s.str.cat(d))
0 fF 1 rR 2 eE 3 eE 4 tT 5 uU 6 tT 7 sS dtype: string
Nếu như xuất hiện NA thì ta có thể dùng tham số na_rep để điền vào các giá trị bị khuyết:
s = pd.Series(['f','r','e','e','t','u','t','s'], dtype='string') d = ['F', 'R', None, 'E', 'T', None, 'T', 'S'] print(s.str.cat(d, na_rep='--'))
0 fF 1 rR 2 e-- 3 eE 4 tT 5 u-- 6 tT 7 sS dtype: string
Nối một DataFrame với Series
Ta hoàn toàn có thể nối một DataFrame với một Series tương tự như trên:
s = pd.Series(['f','r','e','e','t','u','t','s'], dtype='string') d = pd.Series(['F', 'R', None, 'E', 'T', None, 'T', 'S']) f = pd.Series(np.arange(8), dtype='string') s.str.cat(pd.concat([d, f], axis=1), na_rep='-')
0 fF0 1 rR1 2 e-2 3 eE3 4 tT4 5 u-5 6 tT6 7 sS7 dtype: string
Nối các object với Index có trật tự
Chúng ta có thể nối các object (DataFrame, Series) với nhau với trật tự của Index khác nhau. Khi đó tuỳ thuộc vào tham số join (mặc định là 'left'): 'left', 'outer', 'inner' hoặc 'right' mà kết quả sẽ khác nhau:
s = pd.Series(['f','r','e','e'], dtype='string') f = pd.Series([1, 2, 3, 4], index=[1, 3, 2, 0], dtype='string') print("s Series: \n", s) print("f Series: \n", f) print("join = left: \n", s.str.cat(f)) print("\njoin = right: \n", s.str.cat(f, join='right')) print("\njoin = inner: \n", s.str.cat(f, join='inner')) print("\njoin = outer: \n", s.str.cat(f, join='outer'))
s Series: 0 f 1 r 2 e 3 e dtype: string f Series: 1 1 3 2 2 3 0 4 dtype: string join = left: 0 f4 1 r1 2 e3 3 e2 dtype: string join = right: 1 r1 3 e2 2 e3 0 f4 dtype: string join = inner: 0 f4 1 r1 2 e3 3 e2 dtype: string join = outer: 0 f4 1 r1 2 e3 3 e2 dtype: string
3. Ví dụ thực tế
Chúng ta sẽ đi đến một ví dụ thực tế, bộ dữ liệu ta sử dụng sẽ là dữ liệu về tên và một số thông tin liên quan của các hành khách trên tàu Titanic, các bạn có thể tải về ở đây.
Đầu tiên ta sẽ import dữ liệu và xem qua một số cột của tập dữ liệu này:
titanic = pd.read_excel('./titanic_name.xlsx') print(titanic.head())
Sống sót Khoang Tên \ 0 0 3 Braund, Mr. Owen Harris 1 1 1 Cumings, Mrs. John Bradley (Florence Briggs Th... 2 1 3 Heikkinen, Miss. Laina 3 1 1 Futrelle, Mrs. Jacques Heath (Lily May Peel) 4 0 3 Allen, Mr. William Henry Giới tính Tuổi Vé Giá vé 0 male 22.0 A/5 21171 7.2500 1 female 38.0 PC 17599 71.2833 2 female 26.0 STON/O2. 3101282 7.9250 3 female 35.0 113803 53.1000 4 male 35.0 373450 8.0500
Ta có thể thấy họ và tên của những người trên tàu được phân cách bởi dấu phẩy, vậy ta có thể lấy được họ bằng cách:
surname = titanic['Tên'].str.split(',') print(surname)
0 [Braund, Mr. Owen Harris] 1 [Cumings, Mrs. John Bradley (Florence Briggs ... 2 [Heikkinen, Miss. Laina] 3 [Futrelle, Mrs. Jacques Heath (Lily May Peel)] 4 [Allen, Mr. William Henry] ... 886 [Montvila, Rev. Juozas] 887 [Graham, Miss. Margaret Edith] 888 [Johnston, Miss. Catherine Helen "Carrie"] 889 [Behr, Mr. Karl Howell] 890 [Dooley, Mr. Patrick] Name: Tên, Length: 891, dtype: object
Và ta dễ dàng thêm một cột mới chứa họ của hành khách như sau:
titanic['Họ'] = surname.str.get(0) print(titanic['Họ'])
0 Braund 1 Cumings 2 Heikkinen 3 Futrelle 4 Allen ... 886 Montvila 887 Graham 888 Johnston 889 Behr 890 Dooley Name: Họ, Length: 891, dtype: object
Ở trong cột "Tên", ta có thể thấy trước tên sẽ là danh xưng tương ứng, chẳng hạn như Mr., Mrs., Dr.,... Ta có thể sử dụng phương thức contains để tìm ra những hành khách là Tiến sĩ trên tàu Titanic:
dr_list = titanic['Tên'].str.contains('Dr.') print("Dr. List: \n", dr_list) print("\nTổng số tiến sĩ trên tàu: ", dr_list.sum()) print("\nDanh sách những hành khách là tiến sĩ: ", titanic[dr_list])
Dr. List: 0 False 1 False 2 False 3 False 4 False ... 886 False 887 False 888 False 889 False 890 False Name: Tên, Length: 891, dtype: bool Tổng số tiến sĩ trên tàu: 11 Danh sách những hành khách là tiến sĩ: Sống sót Khoang Tên \ 47 1 3 O'Driscoll, Miss. Bridget 130 0 3 Drazenoic, Mr. Jozef 245 0 1 Minahan, Dr. William Edward 317 0 2 Moraweck, Dr. Ernest 398 0 2 Pain, Dr. Alfred 416 1 2 Drew, Mrs. James Vivian (Lulu Thorne Christian) 632 1 1 Stahelin-Maeglin, Dr. Max 660 1 1 Frauenthal, Dr. Henry William 679 1 1 Cardeza, Mr. Thomas Drake Martinez 766 0 1 Brewe, Dr. Arthur Jackson 796 1 1 Leader, Dr. Alice (Farnham) Giới tính Tuổi Vé Giá vé Họ 47 female NaN 14311 7.7500 O'Driscoll 130 male 33.0 349241 7.8958 Drazenoic 245 male 44.0 19928 90.0000 Minahan 317 male 54.0 29011 14.0000 Moraweck 398 male 23.0 244278 10.5000 Pain 416 female 34.0 28220 32.5000 Drew 632 male 32.0 13214 30.5000 Stahelin-Maeglin 660 male 50.0 PC 17611 133.6500 Frauenthal 679 male 36.0 PC 17755 512.3292 Cardeza 766 male NaN 112379 39.6000 Brewe 796 female 49.0 17465 25.9292 Leader
Ta thấy cột giới tính có 2 giá trị là male và female là tiếng Anh trong khi tên cột lại là tiếng Việt. Chúng ta có thể dùng phương thức replace để sửa lại:
titanic['Giới tính'] = titanic['Giới tính'].replace({'male': 'Đàn ông', 'female': 'Phụ nữ'}) print(titanic.head())
Sống sót Khoang Tên \ 0 0 3 Braund, Mr. Owen Harris 1 1 1 Cumings, Mrs. John Bradley (Florence Briggs Th... 2 1 3 Heikkinen, Miss. Laina 3 1 1 Futrelle, Mrs. Jacques Heath (Lily May Peel) 4 0 3 Allen, Mr. William Henry Giới tính Tuổi Vé Giá vé Họ 0 Đàn ông 22.0 A/5 21171 7.2500 Braund 1 Phụ nữ 38.0 PC 17599 71.2833 Cumings 2 Phụ nữ 26.0 STON/O2. 3101282 7.9250 Heikkinen 3 Phụ nữ 35.0 113803 53.1000 Futrelle 4 Đàn ông 35.0 373450 8.0500 Allen
Sử dụng phương thức len ta có thể tìm được hành khách có tên dài nhất và ngắn nhất trên tàu Titanic:
name_len = titanic['Tên'].str.len() idx_max = name_len.idxmax() print("Người có tên dài nhất:", titanic['Tên'][idx_max]) idx_min = name_len.idxmin() print("Người có tên ngắn nhất:", titanic['Tên'][idx_min])
Người có tên dài nhất: Penasco y Castellana, Mrs. Victor de Satode (Maria Josefa Perez de Soto y Vallejo) Người có tên ngắn nhất: Lam, Mr. Ali
Hành khách trên tàu có tên dài nhất là Mrs. Maria Josefa Perezde Soto y Vallejo Peñasco y Castellana đến từ Tây Ban Nha, còn người có tên ngắn nhất là Mr Ali Lam, một du khách tới từ Hong Kong, cả 2 đều được cứu sống sau vụ tai nạn này.
4. Tổng kết
Vậy là ta đã hoàn thành bài học về dữ liệu kiểu văn bản trong Pandas, đây là một kiểu dữ liệu rất phổ biến bên cạnh dữ liệu số thường thấy. Với bộ dữ liệu trên các bạn hãy thử thêm nhiều thao tác hơn với những phương thức mình đã giới thiệu ở trên để hiểu sâu hơn nhé. Hẹn gặp các bạn ở bài tiếp theo.