查找极坐标数据框中各组之间的所有差异

问题描述 投票:0回答:1

我有一个极坐标数据框,我正在尝试查找一个键上的组之间的多个列上的差异(其值已更改的字段)。数据框中可以有多个组和多个列。这些组本质上是 int 格式的日期时间 (YYYYMMDD)

我如何找到日期上(任何)列有新值的行。

样本数据:

raw_df = pl.DataFrame([
    {'id': 'AAPL','update_time': 20241112,'status':'trading', 'underlying': 'y'},
    {'id': 'MSFT','update_time': 20241113,'status': 'trading', 'underlying': 'x'},
    {'id': 'NVDA','update_time': 20241112,'status': 'trading', 'underlying': 'z'},
    {'id': 'MSFT','update_time': 20241112,'status': 'pending','underlying': 'x'},
    {'id': 'AAPL','update_time': 20241113,'status': 'trading', 'underlying': 'y'},
    {'id': 'NVDA','update_time': 20241113,'status': 'trading', 'underlying': 'z'},
    {'id': 'TSLA','update_time': 20241112,'status': 'closed', 'underlying': 'v'},
    ]
)

expected_df = pl.DataFrame([
    {'id': 'MSFT','update_time': 20241112,'status':'pending', 'underlying': 'x'},
    {'id': 'MSFT','update_time': 20241113,'status': 'trading', 'underlying': 'x'},
    ]
)

以下是数据输入的样子。

shape: (7, 4)
┌──────┬─────────────┬─────────┬────────────┐
│ id   ┆ update_time ┆ status  ┆ underlying │
│ ---  ┆ ---         ┆ ---     ┆ ---        │
│ str  ┆ i64         ┆ str     ┆ str        │
╞══════╪═════════════╪═════════╪════════════╡
│ AAPL ┆ 20241112    ┆ trading ┆ y          │
│ MSFT ┆ 20241113    ┆ trading ┆ x          │
│ NVDA ┆ 20241112    ┆ trading ┆ z          │
│ MSFT ┆ 20241112    ┆ pending ┆ x          │
│ AAPL ┆ 20241113    ┆ trading ┆ y          │
│ NVDA ┆ 20241113    ┆ trading ┆ z          │
│ TSLA ┆ 20241112    ┆ closed  ┆ v          │
└──────┴─────────────┴─────────┴────────────┘

下面是预期的结果,显示了 id、更新时间和已更改的字段。如果更改/更新的字段超过 1 个,理想情况下应将其放入新行。

我正在尝试查找已更改的字段,并按键“id”上的“update_time”分组。需要注意的是,一个组中可能存在一些 id,但另一个组中不存在,例如“TSLA”。因此,这些不常见的 id 或组之间的交集可以被忽略。由于只有 MSFT 的状态发生了更改,因此应将其过滤到已更新的两行。字段更改只能在除 update_time 之外的所有其他列上完成,update_time 是我们用来分组的依据。

shape: (2, 3)
┌──────┬─────────────┬─────────┐
│ id   ┆ update_time ┆ status  │
│ ---  ┆ ---         ┆ ---     │
│ str  ┆ i64         ┆ str     │
╞══════╪═════════════╪═════════╡
│ MSFT ┆ 20241112    ┆ pending │
│ MSFT ┆ 20241113    ┆ trading │
└──────┴─────────────┴─────────┴

无法弄清楚如何做到这一点,但这是我最接近的,它无法解决前面提到的警告。

def find_updated_field_differences(df):
        columns_to_check = [col for col in df.columns if col != 'id' and col != 'update_time']

        sorted_df = df.sort('update_time')
        grouped_df = sorted_df.groupby(["update_time"])
        
        result_data = []
        
        for group_key, group_df in grouped_df:
            print(group_df)
    
            for col in columns_to_check:

                group_df = group_df.with_columns(
                    (pl.col(col) != pl.col(col).shift()).alias(f"{col}_changed")
                )
            
            differing_rows = group_df.filter(
                pl.any([pl.col(f"{col}_changed") for col in columns_to_check])
            )


            result_data.append(differing_rows)
        
        differing_df = pl.concat(result_data)
        
        differing_df = differing_df.sort("id")
        
        return differing_df

任何帮助将不胜感激!

python dataframe python-polars data-engineering
1个回答
0
投票

你的方法有点过于复杂了。我的建议是,你首先按

id
update_time
对数据进行排序,然后移动数据以准备比较。之后,您可以识别
id
相同但存在差异的行:

import polars as pl

def find_updated_field_differences(df):
    sorted_df = df.sort(['id', 'update_time'])
    
    shifted_df = sorted_df.shift(-1)

    mask = (
        (sorted_df['id'] == shifted_df['id']) &
        ((sorted_df['status'] != shifted_df['status']) | (sorted_df['underlying'] != shifted_df['underlying']))
    )

    start_changes = sorted_df.filter(mask)
    end_changes = sorted_df.shift(-1).filter(mask)
    differing_df = pl.concat([start_changes, end_changes]).unique()

    return differing_df.sort(['id', 'update_time'])

raw_df = pl.DataFrame([
    {'id': 'AAPL', 'update_time': 20241112, 'status': 'trading', 'underlying': 'y'},
    {'id': 'MSFT', 'update_time': 20241113, 'status': 'trading', 'underlying': 'x'},
    {'id': 'NVDA', 'update_time': 20241112, 'status': 'trading', 'underlying': 'z'},
    {'id': 'MSFT', 'update_time': 20241112, 'status': 'pending', 'underlying': 'x'},
    {'id': 'AAPL', 'update_time': 20241113, 'status': 'trading', 'underlying': 'y'},
    {'id': 'NVDA', 'update_time': 20241113, 'status': 'trading', 'underlying': 'z'},
    {'id': 'TSLA', 'update_time': 20241112, 'status': 'closed', 'underlying': 'v'},
])

result_df = find_updated_field_differences(raw_df)
print(result_df)

这给了你

shape: (2, 4)
┌──────┬─────────────┬─────────┬────────────┐
│ id   ┆ update_time ┆ status  ┆ underlying │
│ ---  ┆ ---         ┆ ---     ┆ ---        │
│ str  ┆ i64         ┆ str     ┆ str        │
╞══════╪═════════════╪═════════╪════════════╡
│ MSFT ┆ 20241112    ┆ pending ┆ x          │
│ MSFT ┆ 20241113    ┆ trading ┆ x          │
© www.soinside.com 2019 - 2024. All rights reserved.