如何逐次计算状态转移概率?(基于Pandas的0-1序列分析)
解决方案
步骤1:生成5步区间窗口
根据需求,我们需要生成对应试次区间来逐次计算转移概率。这里提供两种常见的区间生成方式:
- 非重叠窗口:每5个试次为一个独立窗口,覆盖全部40次试次(前4个窗口属于Block1,后4个属于Block2)
window_size = 5 # 生成区间:(0,5), (5,10), ..., (35,40) trial_ranges = [(i, i+window_size) for i in range(0, len(sc), window_size)] - 滑动窗口:每次移动1个试次,生成更精细的连续窗口,适合观察细微趋势变化
window_size = 5 trial_ranges = [(i, i+window_size) for i in range(len(sc) - window_size + 1)]
步骤2:优化转移概率计算
原有的计算函数可以用Pandas的crosstab简化,更高效且易维护:
import pandas as pd def transition_matrix(transitions): # 生成连续状态转移对 pairs = pd.DataFrame({ 'from': transitions[:-1], 'to': transitions[1:] }) # 计算归一化的转移矩阵(行求和为1) mat = pd.crosstab(pairs['from'], pairs['to'], normalize='index') # 确保4种转移类型都存在(避免部分窗口缺失对应转移的情况) mat = mat.reindex(index=[0,1], columns=[0,1], fill_value=0) return mat.values
步骤3:逐次计算并可视化趋势
方式1:多窗口热图对比
适合非重叠窗口的直观对比,清晰展示每个窗口的转移概率分布:
import matplotlib.pyplot as plt import seaborn as sns fig, axes = plt.subplots(2, 4, figsize=(16, 8)) axes = axes.flatten() for i, (start, end) in enumerate(trial_ranges): sub_sc = sc[start:end] trans_mat = transition_matrix(sub_sc) sns.heatmap(trans_mat, annot=True, fmt=".2f", cmap="YlGnBu", ax=axes[i], cbar=False) axes[i].set_xlabel('目标状态') axes[i].set_ylabel('起始状态') # 标记所属Block block = 1 if end <=20 else 2 axes[i].set_title(f'窗口 {start+1}-{end}\nBlock {block}') plt.tight_layout() plt.show()
方式2:折线图展示趋势变化
更直观观察从Block1到Block2的4种转移概率的连续变化趋势:
# 存储所有窗口的转移概率结果 results = [] for start, end in trial_ranges: sub_sc = sc[start:end] trans_mat = transition_matrix(sub_sc) results.append({ 'window_start': start+1, 'window_end': end, 'block': 1 if end <=20 else 2, '0→0': trans_mat[0][0], '0→1': trans_mat[0][1], '1→0': trans_mat[1][0], '1→1': trans_mat[1][1] }) # 转换为DataFrame用于绘图 trend_df = pd.DataFrame(results) plt.figure(figsize=(12,6)) sns.lineplot(data=trend_df, x='window_start', y='0→0', label='0→0', marker='o') sns.lineplot(data=trend_df, x='window_start', y='0→1', label='0→1', marker='s') sns.lineplot(data=trend_df, x='window_start', y='1→0', label='1→0', marker='^') sns.lineplot(data=trend_df, x='window_start', y='1→1', label='1→1', marker='*') # 标记Block1和Block2的分界 plt.axvline(x=20, color='r', linestyle='--', label='Block 1/2 分界') plt.xlabel('窗口起始试次') plt.ylabel('转移概率') plt.title('从Block1到Block2的转移概率趋势') plt.legend() plt.grid(True) plt.show()
完整可运行代码示例
import pandas as pd import numpy as np import matplotlib.pyplot as plt import seaborn as sns # 初始化40次试次数据 df = pd.DataFrame() df['response'] = [0,1,1,0,1,0,1,0,1,0,1,1,1,1,1,0,0,1,1,0, 1,0,0,1,1,1,0,0,0,1,0,1,1,0,0,1,1,0,0,1] sc = df['response'].tolist() sc = [x for x in sc if not np.isnan(x)] def transition_matrix(transitions): pairs = pd.DataFrame({ 'from': transitions[:-1], 'to': transitions[1:] }) mat = pd.crosstab(pairs['from'], pairs['to'], normalize='index') mat = mat.reindex(index=[0,1], columns=[0,1], fill_value=0) return mat.values # 生成非重叠5步窗口 window_size = 5 trial_ranges = [(i, i+window_size) for i in range(0, len(sc), window_size)] # 生成趋势折线图 results = [] for start, end in trial_ranges: sub_sc = sc[start:end] trans_mat = transition_matrix(sub_sc) results.append({ 'window_start': start+1, 'window_end': end, 'block': 1 if end <=20 else 2, '0→0': trans_mat[0][0], '0→1': trans_mat[0][1], '1→0': trans_mat[1][0], '1→1': trans_mat[1][1] }) trend_df = pd.DataFrame(results) plt.figure(figsize=(12,6)) sns.lineplot(data=trend_df, x='window_start', y='0→0', label='0→0', marker='o') sns.lineplot(data=trend_df, x='window_start', y='0→1', label='0→1', marker='s') sns.lineplot(data=trend_df, x='window_start', y='1→0', label='1→0', marker='^') sns.lineplot(data=trend_df, x='window_start', y='1→1', label='1→1', marker='*') plt.axvline(x=20, color='r', linestyle='--', label='Block 1/2 分界') plt.xlabel('窗口起始试次') plt.ylabel('转移概率') plt.title('从Block1到Block2的转移概率趋势') plt.legend() plt.grid(True) plt.show()
内容的提问来源于stack exchange,提问作者Kshtj
相关产品推荐
相关产品推荐

