基于另一个具有日期时间范围的数据帧的新真/假数据帧

2024-10-01 19:31:25 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个长期无法解决的问题。我想用插值(每一分钟)和N个附加列生成新的DataFrame,其中N是基本DataFrame中ID列的集合长度

我的数据帧(df)如下所示:

Datetime_ON           Datetime_OFF          ID
2020-01-02 15:21:49   2020-01-02 15:32:44   GB5U
2020-01-02 15:22:40   2020-01-02 15:24:14   GS8U
2020-01-02 15:45:25   2020-01-02 15:59:18   GS8U
2020-01-02 16:07:11   2020-01-02 16:16:50   GB5U

现在我想创建一个新的数据帧(new_df),其中包含日期时间范围从min(df['Datetime_ON'])max(df['Datetime_OFF'])的插值

new_df = pd.DataFrame(pd.date_range(start=min(df['Datetime_ON']), end=max(df['Datetime_OFF']), freq="1min"))

Datetime
2020-01-02 15:21:00
2020-01-02 15:22:00
2020-01-02 15:23:00
...
2020-01-02 16:16:00

现在我想从ID集合中添加N个列,这些列来自dfDrataFrameset(df['ID'])如果Datetime中的Datetime列在Datetime\U onDatetime\U OFF之间,则根据条件将Datetime值填入True/False列中

我的预期产出:

Datetime              GB5U   GS8U
2020-01-02 15:21:00   False  False
2020-01-02 15:22:00   True   False
2020-01-02 15:23:00   True   True
2020-01-02 15:24:00   True   True
2020-01-02 15:25:00   True   False
...
2020-01-02 16:15:00   True   False
2020-01-02 16:16:00   True   False

问题是我的dataframe有超过700k行,ID集的长度超过100(超过100个新列)。我尝试使用iterrows()和apply函数,但速度非常慢。有没有办法在合理的时间内解决这个问题


Tags: 数据idfalsetruedataframedfnewdatetime
1条回答
网友
1楼 · 发布于 2024-10-01 19:31:25

第一次尝试

这里有一个建议。我不确定它是否真的比你已经尝试过的更快,但也许值得一试:

from functools import reduce
from operator import or_

# Just to make new_df as in the example
new_df = pd.DataFrame(pd.date_range('2020-01-02 15:21:00',
                                    '2020-01-02 16:16:00',
                                    freq="1min"),
                                    columns=['Datetime'])

# To make the following statement more compact
df.rename(columns={'Datetime_ON': 'ON', 'Datetime_OFF': 'OFF'}, inplace=True)

new_df = pd.concat(
        [new_df]
        + [
            (reduce(or_,((start <= new_df) & (new_df <= stop)
                         for start, stop in zip(group['ON'], group['OFF'])))
                    .rename({'Datetime': key}, axis='columns'))            
            for key, group in df.groupby('ID')
          ],
        axis='columns'
    ).set_index('Datetime', drop=True)

结果:

                      GB5U   GS8U
Datetime                         
2020-01-02 15:21:00  False  False
2020-01-02 15:22:00   True  False
2020-01-02 15:23:00   True   True
2020-01-02 15:24:00   True   True
2020-01-02 15:25:00   True  False
...
2020-01-02 16:15:00   True  False
2020-01-02 16:16:00   True  False

第二次尝试

我对这个问题想得更多一些,可能会找到一个更快的方法。想法是更直接地设置True值:

# new_df as in the example
new_df = pd.DataFrame(pd.date_range('2020-01-02 15:21:00',
                                    '2020-01-02 16:16:00',
                                    freq="1min"),
                                    columns=['Datetime'])

# To make the following statement more compact
df.rename(columns={'Datetime_ON': 'ON', 'Datetime_OFF': 'OFF'}, inplace=True)

# To make sure the columns are in datetime format
df.ON = pd.to_datetime(df.ON)
df.OFF = pd.to_datetime(df.OFF)

idx = new_df.Datetime
dfs = []
for key, group in df.groupby('ID'):
    trues = [
                minute
                for start, stop in zip(group.ON, group.OFF)
                for minute in pd.date_range(start.ceil('min'), stop.floor('min'), freq='1min')
            ]
    df_group = pd.DataFrame({key: False}, index=idx)
    df_group.loc[trues, key] = True
    dfs.append(df_group)

new_df = pd.concat(dfs, axis='columns')

对于这个例子,结果是相同的。我认为这应该是一般情况,但我还不是100%肯定。同样,我也不确定效率,因为很多都取决于真实数据

相关问题 更多 >

    热门问题