Pandas 字串處理
Pandas 透過 .str accessor 提供了豐富的字串處理方法,可以對整個 Series 進行向量化的字串操作。
基本用法
import pandas as pd
s = pd.Series(['Alice', 'Bob', 'Charlie'])
# 使用 .str 存取字串方法
print(s.str.upper())
0 ALICE
1 BOB
2 CHARLIE
dtype: object
大小寫轉換
s = pd.Series(['Hello World', 'PYTHON', 'pandas'])
s.str.lower() # 全部小寫
s.str.upper() # 全部大寫
s.str.title() # 每個單字首字母大寫
s.str.capitalize() # 只有第一個字母大寫
s.str.swapcase() # 大小寫互換
移除空白
s = pd.Series([' hello ', ' world ', 'python'])
s.str.strip() # 移除前後空白
s.str.lstrip() # 移除左邊空白
s.str.rstrip() # 移除右邊空白
# 移除特定字元
s.str.strip('!')
字串長度
s = pd.Series(['hello', 'world', 'python'])
print(s.str.len())
0 5
1 5
2 6
dtype: int64
搜尋與判斷
contains():是否包含
s = pd.Series(['apple', 'banana', 'cherry'])
print(s.str.contains('an'))
0 False
1 True
2 False
dtype: bool
# 不區分大小寫
s.str.contains('An', case=False)
# 使用正規表達式
s.str.contains(r'^a', regex=True) # 以 a 開頭
# 搭配過濾
df = pd.DataFrame({'fruit': ['apple', 'banana', 'cherry']})
df[df['fruit'].str.contains('an')]
startswith() / endswith()
s.str.startswith('a') # 是否以 a 開頭
s.str.endswith('y') # 是否以 y 結尾
match():正規表達式匹配
s = pd.Series(['A123', 'B456', '789'])
s.str.match(r'^[A-Z]') # 是否以大寫字母開頭
取代
replace()
s = pd.Series(['hello-world', 'foo-bar'])
# 簡單取代
s.str.replace('-', ' ')
# 使用正規表達式
s.str.replace(r'\d+', 'NUM', regex=True)
# 不區分大小寫
s.str.replace('HELLO', 'hi', case=False)
分割與合併
split()
s = pd.Series(['a,b,c', 'd,e,f'])
# 分割成 list
print(s.str.split(','))
0 [a, b, c]
1 [d, e, f]
dtype: object
# 展開成多個欄位
df = s.str.split(',', expand=True)
print(df)
0 1 2
0 a b c
1 d e f
# 限制分割次數
s.str.split(',', n=1) # 只分割一次
join()
s = pd.Series([['a', 'b'], ['c', 'd', 'e']])
s.str.join('-')
# 0 a-b
# 1 c-d-e
cat():串接字串
s = pd.Series(['a', 'b', 'c'])
# 串接所有元素
s.str.cat() # 'abc'
s.str.cat(sep='-') # 'a-b-c'
# 與另一個 Series 串接
s2 = pd.Series(['1', '2', '3'])
s.str.cat(s2, sep='-') # ['a-1', 'b-2', 'c-3']
擷取與切片
索引存取
s = pd.Series(['hello', 'world'])
s.str[0] # 第一個字元
s.str[-1] # 最後一個字元
s.str[1:3] # 切片
slice()
s.str.slice(0, 3) # 前三個字元
s.str.slice(2) # 從第三個字元開始
extract():正規表達式擷取
s = pd.Series(['a1b2', 'c3d4', 'e5f6'])
# 擷取數字
s.str.extract(r'(\d+)')
# 擷取多個群組
df = s.str.extract(r'([a-z])(\d)')
print(df)
0 1
0 a 1
1 c 3
2 e 5
extractall():擷取所有匹配
s = pd.Series(['a1b2', 'c3d4'])
df = s.str.extractall(r'(\d)')
print(df)
填充與對齊
s = pd.Series(['a', 'bb', 'ccc'])
s.str.pad(5, side='left', fillchar='0') # 左側填充
s.str.pad(5, side='right', fillchar='0') # 右側填充
s.str.center(5, fillchar='-') # 置中
s.str.zfill(5) # 左側補零
其他常用方法
s = pd.Series(['hello world', 'foo bar'])
s.str.count('o') # 計算出現次數
s.str.find('o') # 找出第一次出現的位置
s.str.rfind('o') # 找出最後一次出現的位置
s.str.isdigit() # 是否全部是數字
s.str.isalpha() # 是否全部是字母
s.str.isalnum() # 是否全部是英數字
s.str.isnumeric() # 是否是數值字元
s.str.isspace() # 是否全部是空白
s.str.repeat(2) # 重複 2 次
s.str.wrap(5) # 自動換行
處理空值
字串方法預設會忽略 NaN:
s = pd.Series(['hello', None, 'world'])
print(s.str.upper())
0 HELLO
1 NaN
2 WORLD
dtype: object
如果需要填補空值:
s.str.upper().fillna('')
實際應用
清理資料
df = pd.DataFrame({
'name': [' Alice ', 'BOB', 'charlie']
})
df['name'] = df['name'].str.strip().str.title()
解析資料
df = pd.DataFrame({
'email': ['alice@gmail.com', 'bob@yahoo.com']
})
# 提取 @ 前面的使用者名稱
df['username'] = df['email'].str.split('@').str[0]
# 提取網域
df['domain'] = df['email'].str.extract(r'@(.+)$')