這次我將分享三個實際案例,讓大家看看列表分列的一些實際應用。
首先,我們先導包並設置Pandas顯示參數:
import pandas as pd
pd.set_option("display.max_colwidth", 100)
正則提取並分列需求:
讀取數據:
df = pd.read_excel("正則提取與分列.xlsm", usecols=[0])
df.head()結果:
實現代碼:
result = df.copy()
result["tmp"] = result["補回原因"].str.findall("([\d.]+[到至][\d.]+)")
result = result.agg({"補回原因": lambda x: x, "tmp": pd.Series}).droplevel(0, axis=1)
result.head()結果:
分步解析:
df["tmp"] = df["補回原因"].str.findall("([\d.]+[到至][\d.]+)")
df.head(5)結果:
這步使用正則提取出每個日期字符串,[\d.]+表示連續的數字或.用於匹配時間字符串,兩個時間之間的連接字符可能是到或至。
然後我使用agg函數直接對Datafream分列:
df.agg({"補回原因": lambda x: x, "tmp": pd.Series})結果:
由於列索引多了一級,所以需要刪除:
df.agg({"補回原因": lambda x: x, "tmp": pd.Series}).droplevel(0, axis=1).head()結果:
droplevel(0, axis=1)用於刪除多級索引指定的級別,axis=0可以刪除行索引,axis=1則可以刪除列索引,第一參數表示刪除級別0。當然如果列索引存在名稱時還可以傳入名稱字符串,可參考官網文檔:
df = pd.DataFrame([
... [1, 2, 3, 4],
... [5, 6, 7, 8],
... [9, 10, 11, 12]
... ]).set_index([0, 1]).rename_axis(['a', 'b'])
>>> df.columns = pd.MultiIndex.from_tuples([
... ('c', 'e'), ('d', 'f')
... ], names=['level_1', 'level_2'])
>>> df
level_1 c d
level_2 e f
a b
1 2 3 4
5 6 7 8
9 10 11 12
>>> df.droplevel('a')
level_1 c d
level_2 e f
b
2 3 4
6 7 8
10 11 12
>>> df.droplevel('level2', axis=1)
level_1 c d
a b
1 2 3 4
5 6 7 8
9 10 11 12
分組聚合併分列需求:
首先,讀取數據:
df = pd.read_excel("分組聚合併分列.xlsx")
df結果:
實現代碼:
(
df.groupby("姓名")["得分"]
.apply(list)
.apply(pd.Series)
.fillna("")
.rename(columns=lambda x: f"得分{x+1}")
.reset_index()
.astype({"得分1":"int8"})
)結果:
分布解析:
首先將每個姓名的得分聚合成列表,並最終返回一個Series:
df.groupby("姓名")["得分"].apply(list)結果:
姓名
孫四娘 [7, 28]
看見星光 [88, 28, 23]
看見月光 [69, 10, 87]
老祝 [51, 29]
馬青梅 [99]
Name: 得分, dtype: object當然,這步的標準寫法應該是使用Series的內部方法:
df.groupby("姓名")["得分"].apply(lambda x:x.to_list())使用Series內部方法的性能比python列表方法轉換快一些。
作為一個Series就可以通過將每個列表元素轉換為Series,從而最終返回一個分列的Datafream:
_.apply(pd.Series)結果:
注意:_在ipython表示上一個輸出返回的結果,jupyter還額外支持_num表示num編號單元格的輸出。
_.fillna("")結果:
fillna表示填充缺失值,傳入""表示將缺失值填充為空字符串。
下面重命名一下列名:
_.rename(columns=lambda x: f"得分{x+1}")結果:
然後還原索引:
_.reset_index()結果:
發現結果中有一列,不是整數,所以還原成整數(總分100分,8位足夠存儲):
_.astype({"得分1":"int8"})結果:
解析json字符串並字典分列需求:
首先讀取數據:
df = pd.read_excel("字典分列.xlsx")
df.head()結果:
處理代碼:
result = df.features.apply(eval).apply(pd.Series)
result["counts"] = df.counts
result結果:
儲存條件品牌推薦理由品種食用方式是否進口特色服務是否有機counts0常溫NaNNaNNaNNaNNaNNaNNaN331冷藏NaNNaNNaNNaNNaNNaNNaN242常溫禾煜NaNNaNNaNNaNNaNNaN223常溫妙潔NaNNaNNaNNaNNaNNaN164冷凍NaNNaNNaNNaNNaNNaNNaN142083常溫樂事夠薄夠脆NaNNaNNaNNaNNaN12084冷藏NaN生態種植黃瓜NaNNaNNaN有機12085冷藏NaN腥味較淡鯽魚NaNNaN免費宰殺NaN12086冷藏NaN甜脆可口佛手瓜NaNNaNNaNNaN12087冷藏叮咚日日鮮全程可追溯豬小排NaNNaNNaNNaN12088 rows × 9 columns
淺析:
df.features.apply(eval)用於將features列的每個json字符串解析為字典對象。
**.apply(pd.Series)則可以將每個字典對象轉換成Series,則可以將該字典擴展到多列,並將原始的Series轉換為Datafream。
而result["counts"] = df.counts則將原始數據的counts列添加到結果列中。