Python:处理不同大小的数据框以根据日期时间条件创建新列

时间:2019-12-04 14:37:12

标签: python pandas dataframe datetime

我在Python中有2个大小不同的数据框。较小的数据框具有2个datetime列,一列用于开始日期时间,一列用于结束日期时间。另一个数据框更大(更多的行和列),并且具有一个datetime列。

df A

Date_hour_beginning   Date_hour_end
3/8/2019 18:35        3/8/2019 19:45
4/8/2019 14:22        4/8/2019 14:55

df B

Date_hour         compression
3/8/2019 18:37      41
3/8/2019 18:55      47
3/8/2019 19:30      55
3/8/2019 19:51      51
4/8/2019 14:10      53
4/8/2019 14:35      48
4/8/2019 14:51      51
4/8/2019 15:02      58

我想将压缩的平均值和幅度添加到涵盖日期时间范围的df_A。要获得以下结果:

df_A
Date_hour_beginning   Date_hour_end     mean_compression     amplitude
3/8/2019 18:35        3/8/2019 19:45        47.66              14
4/8/2019 14:22        4/8/2019 14:55        49.5               3

我尝试了np.where和groupby,但我不知道,但是我遇到了数据框形状不匹配的错误。

4 个答案:

答案 0 :(得分:2)

# create test dataframes
df_A = pd.DataFrame(
    {
        "Date_hour_beginning": ["3/8/2019 18:35", "4/8/2019 14:22"],
        "Date_hour_end": ["3/8/2019 19:45", "4/8/2019 14:55"],
    }
)
df_B = pd.DataFrame(
    {
        "Date_hour": [
            "3/8/2019 18:37",
            "3/8/2019 18:55",
            "3/8/2019 19:30",
            "3/8/2019 19:51",
            "4/8/2019 14:10",
            "4/8/2019 14:35",
            "4/8/2019 14:51",
            "4/8/2019 15:02",
        ],
        "compression": [41, 47, 55, 51, 53, 48, 51, 58],
    }
)

# convert to datetime
df_A['Date_hour_beginning'] = pd.to_datetime(df_A['Date_hour_beginning'])
df_A['Date_hour_end'] = pd.to_datetime(df_A['Date_hour_end'])
df_B['Date_hour'] = pd.to_datetime(df_B['Date_hour'])

# accumulate compression values per range
df_A["compression"] = df_A.apply(
    lambda row: df_B.loc[
        (df_B["Date_hour"] >= row["Date_hour_beginning"])
        & (df_B["Date_hour"] <= row["Date_hour_end"]),
        "compression",
    ].values.tolist(),
    axis=1,
)

# calculate mean compression and amplitude
df_A['mean_compression'] = df_A['compression'].apply(lambda x: sum(x) / len(x))
df_A['amplitude'] = df_A['compression'].apply(lambda x: max(x) - min(x))

答案 1 :(得分:2)

这是我的解决方案。这是eva-vw的更详细的版本(也许更易读?)。 eva-vw使用.apply()方法,这是循环遍历数据帧行的最快方法。但是,只有在您的df_A具有很多行(很多)的情况下,才应该在运行时间上产生重大差异(在这里似乎不是这种情况)。

for i, row in df_A.iterrows() :

    start = row['Date_hour_beginning']
    end = row['Date_hour_end']

    mask = (df_B['Date_hour'] >= start) & (df_B['Date_hour'] <= end) 
    compression_values = df_B.loc[mask, 'compression']

    df_A.loc[i, 'avg comp'] = compression_values.mean()
    df_A.loc[i, 'amp comp'] = compression_values.max() - compression_values.min()

为完整起见,这是我创建数据框的方式:

import numpy as np
import pandas as pd

columns = ['Date_hour_beginning', 'Date_hour_end']

times_1 = pd.to_datetime(['3/8/2019 18:35', '3/8/2019 19:45'])
times_2 =  pd.to_datetime(['4/8/2019 14:22', '4/8/2019 14:55'])

df_A = pd.DataFrame(data=[times_1, times_2], columns=columns)

data_B = [ ['3/8/2019 18:37',      41],
            ['3/8/2019 18:55',      47],
            ['3/8/2019 19:30',      55],
            ['3/8/2019 19:51',      51],
            ['4/8/2019 14:10',      53],
            ['4/8/2019 14:35',      48],
            ['4/8/2019 14:51',      51],
            ['4/8/2019 15:02',      58]]

columns_B = ['Date_hour', 'compression']
df_B = pd.DataFrame(data=data_B, columns=columns_B)

df_B['Date_hour'] = pd.to_datetime(df_B['Date_hour'])

进一步说明:要解决您的问题,您需要遍历df_A的行。这可以通过三种主要方式完成:(i)在数据帧的行索引上使用普通的for循环,(ii)在for方法下使用.iterrows()循环,或使用apply()方法。

我在运行时从最慢到最快命令了它们。我选择了方法(ii)和eva-vw选择了方法(iii)。 .apply()的优点是它是最快的,但对我来说,它的缺点是您必须用单行lambda函数编写要对该行进行的所有操作。 / p>

答案 2 :(得分:1)

使用此:

df_A['Date_hour_beginning'] = pd.to_datetime(df_A['Date_hour_beginning'])
df_A['Date_hour_end'] = pd.to_datetime(df_A['Date_hour_end'])
df_B['Date_hour'] = pd.to_datetime(df_B['Date_hour'])

df_A = df_A.assign(key=1)
df_B = df_B.assign(key=1)
df_merge = pd.merge(df_A, df_B, on='key').drop('key',axis=1)

df_merge = df_merge.query('Date_hour >= Date_hour_beginning and Date_hour <= Date_hour_end')
df_merge['amplitude'] = df_merge.groupby(['Date_hour_beginning','Date_hour_end'])['compression'].transform(lambda x: x.max()-x.min())
df_merge = df_merge.groupby(['Date_hour_beginning','Date_hour_end']).mean()

输出:

                                         compression  amplitude
Date_hour_beginning Date_hour_end                              
2019-03-08 18:35:00 2019-03-08 19:45:00    47.666667       14.0
2019-04-08 14:22:00 2019-04-08 14:55:00    49.500000        3.0

答案 3 :(得分:1)

groupby可以接受索引相同的系列,即

df['Date_hour'] = pd.to_datetime(df['Date_hour'])

df_a['begin'] = pd.to_datetime(df_a['begin'])
df_a['end'] = pd.to_datetime(df_a['end'])

selector = df.apply(lambda x: df_a.query(f'begin <= \'{x["Date_hour"]}\' <= end').index[0], axis=1)

for i_gr, gr in df.groupby(selector):
    print(i_gr, gr)

然后继续使用.mean()或.median()

相关问题