每次 Series 为 True 时拆分 pandas DataFrame

在我们的上一篇文章中,我们探讨了如何每次列为 True 时拆分 pandas DataFrame

此稍微修改的函数也适用于给定的 Series 不是 DataFrame 中的列的情况:

split_dataframe_by_series.py
def split_dataframe_by_series(df, series):
    """
    在给定 series 为 True 的地方拆分 DataFrame。产生多个 dataframe
    """
    previous_index = df.index[0]

    for split_point in df[series].index:
        yield df[previous_index:split_point]
        previous_index = split_point
    # 产生数据集的剩余部分
    try:
        yield df[split_point:]
    except UnboundLocalError:
        pass # 没有分割点 => 忽略

完整示例

我们将使用我们在上一篇关于如何检测 pandas 字符串列/series 中的值变化的文章中构建的 ZeroCrossing 列,该文章本身基于我们关于如何创建 pandas 时间序列 DataFrame 示例数据集的文章。基于该示例,我们添加上面显示的修改后的实用函数:

split_dataframe_full_example.py
import pandas as pd

# 加载预构建的时间序列示例数据集
df = pd.read_csv("https://techoverflow.net/datasets/timeseries-example.csv", parse_dates=["Timestamp"])
df.set_index("Timestamp", inplace=True)

# 创建包含 "Positive" 或 "Negative" 的新列
df["SinePositive"] = (df["Sine"] >= 0).map({True: "Positive", False: "Negative"})
# 创建 "change" 列(布尔值)
df["ZeroCrossing"] = df["SinePositive"].shift() != df["SinePositive"]
# 将第一个条目设置为 False
df["ZeroCrossing"].iloc[0] = False

def split_dataframe_by_series(df, series):
    """
    在给定 series 为 True 的地方拆分 DataFrame。产生多个 dataframe
    """
    previous_index = df.index[0]

    for split_point in df[series].index:
        yield df[previous_index:split_point]
        previous_index = split_point
    # 产生数据集的剩余部分
    try:
        yield df[split_point:]
    except UnboundLocalError:
        pass # 没有分割点 => 忽略

# 打印结果
split_frames = list(split_dataframe_by_series(df, df["ZeroCrossing"]))
print(f"Split DataFrame into {len(split_frames)} separate frames by zero-crossing")

注意根据你的应用程序,将 split_dataframe_to_series() 的结果转换为 list 可能不是必要的。如果可能,我建议直接使用 for 循环迭代数据帧,例如:

iterate_split_frames.py
for df_section in split_dataframe_by_series(df, df["ZeroCrossing"]):
    pass # TODO: 你的代码放在这里!

Check out similar posts by category: Pandas, Python