如何向量化处理含MultiIndex列的DataFrame行比较操作
问题:带MultiIndex列的时间序列DataFrame新增值变化判断列
我有一个带MultiIndex列的时间序列DataFrame,想要新增一组布尔值列,用来标记每行某列的值和上一行是否不同(即值是否发生变化)。比如示例里2022-11-27这一行dave的weight_change为True,因为他的体重从上周的83变成了80,另外两人体重没变化,所以是False。目前我用的是逐行迭代的繁琐方案,想换成可应用于整个DataFrame的向量化方案。
原始迭代实现代码:
import random idx = pd.IndexSlice cols = pd.MultiIndex.from_product([["mike", "matt", "dave"], ['weight', 'drug', 'weight_change']]) index = pd.date_range(start="2022-10-30", end="2022-12-3" ,freq="w", ) df = pd.DataFrame(index=index, columns=cols) for name in ['mike', 'matt', 'dave']: df.loc[:, idx[name,'drug']] = random.sample(['a','b','a','a','a','c','a','c'], k=5) df.loc[:,idx[name, 'weight']] = random.sample([80,80,80,80,82,83,80, 80, 80], k=5) # 繁琐的迭代解决方案 one_row = df.iloc[-2].loc[:,'weight'] != df.iloc[-1].loc[:,'weight'] pd.MultiIndex.from_product([one_row.index, ['weight_change',]]) one_row.index = pd.MultiIndex.from_product([one_row.index, ['weight_change',]]) one_row df.loc['2022-11-27',idx[:,'weight_change']] = one_row
向量化解决方案
针对数值型和非数值型数据,分别可以用以下向量化方法实现:
数值型数据(如体重)
利用diff()计算相邻行的差值,再通过ne(0)判断值是否发生变化,最后重命名列映射到目标标记列。
非数值型数据(如情绪)
由于diff()不支持非数值类型,直接用ne()结合shift()比较当前行与上一行的值是否不同即可。
完整实现代码:
import random idx = pd.IndexSlice cols = pd.MultiIndex.from_product([["mike", "matt", "dave"], [ 'drug', 'mood', 'weight', 'mood_change', 'weight_change']]) index = pd.date_range(start="2022-10-30", end="2022-12-3" ,freq="w", ) df = pd.DataFrame(index=index, columns=cols) for name in ['mike', 'matt', 'dave']: df.loc[:, idx[name,'drug']] = random.sample(['a','b','a','a','a','c','a','c'], k=5) df.loc[:,idx[name, 'mood']] = random.sample(['alert', 'alert', 'dull', 'dull', 'alert', 'alert'], k=5) df.loc[:,idx[name, 'weight']] = random.sample([80,80,80,80,82,83,80, 80, 80], k=5) # 定义原列与标记列的映射关系 d = {'weight':'weight_change', 'mood':'mood_change'} # 处理数值型的weight列 df.loc[df.index[1]:, idx[:, 'weight_change']] = df.loc[df.index[1]:, idx[:, 'weight']].diff().ne(0).rename(columns=d) # 处理非数值型的mood列 df.loc[df.index[1]:, idx[:, 'mood_change']] = df.loc[df.index[1]:, idx[:, 'mood']].ne(df.loc[df.index[1]:, idx[:, 'mood']].shift()).rename(columns=d) df
内容的提问来源于stack exchange,提问作者user3556757
相关产品推荐
相关产品推荐

