在另一个数据帧中的日期之间过滤 pandas 数据帧

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

假设我有两个 pandas 数据框:第一个数据框包含代码和时间上的一些数据(反映在下面示例中的 Col1 和 Col2 列中)。 第二个数据框详细说明了一组日期范围。这个想法是排除日期落在任何边界(在

df_table
中)之间的任何行(在
df_dates
中)。每个代码都有一个或多个(且不同的)界限,或者可能根本没有界限。 下面的代码运行良好并正确完成任务,但它花费了太多时间(第一个数据帧
df_table
有几百万行)。

import pandas as pd
import numpy as np

def filter_date(main_table, table_dates):
    
    idx = table_dates.Code == main_table.Code
    table_dates = table_dates.loc[idx]
    filtering = (table_dates['Start Date'] <= main_table.Timestamp) & (table_dates['End Date'] >= main_table.Timestamp)
    
    return filtering.any()


# Example below
df_table = pd.DataFrame({'Code':['A', 'A', 'A', 'A', 'A', 'A', 'B', 'B', 'B', 'B', 'B', 'B', 'C', 'C'], 'Timestamp':[1,2,3,4,5,6,1,2,3,4,5,6,1,2], 'Col1':np.arange(14), 'Col2':np.arange(14)})
df_dates = pd.DataFrame({'Code':['A', 'A', 'B'], 'Start Date':[1, 5, 1], 'End Date':[2, 6, 3]})
        
df_table['Exclude Date'] = df_table.apply(lambda x: filter_date(x, df_dates), axis=1)
df_table = df_table[df_table['Exclude Date'] == False]
        
print(df_table)

有没有更聪明的方法来做到这一点并避免这种情况

.apply()

python pandas
1个回答
0
投票

你可以尝试这样的事情:

1.创建一个字典,其中包含每个代码的范围

2.检查时间戳值是否存在于该代码的范围内

3.添加包含“是”和“否”值的列。然后您可以在此基础上对数据框进行分组。

看起来更长,但检查字典中列表的值更快。

import pandas as pd
import numpy as np

# Example below
df_table = pd.DataFrame({'Code':['A', 'A', 'A', 'A', 'A', 'A', 'B', 'B', 'B', 'B', 'B', 'B', 'C', 'C'], 'Timestamp':[1,2,3,4,5,6,1,2,3,4,5,6,1,2], 'Col1':np.arange(14), 'Col2':np.arange(14)})
df_dates = pd.DataFrame({'Code':['A', 'A', 'B'], 'Start Date':[1, 5, 1], 'End Date':[2, 6, 3]})
        
#Create Dictionary with boundary ranges for each code value
ranges = {k: [] for k in df_dates['Code'].unique()}

for i in range(len(df_dates)):
    row = df_dates.loc[i]
    ranges[row['Code']].append((row['Start Date'], row['End Date']))


#Check if 'Timestamp' values are in the range and add a 'Yes, 'No' and 'NaN' column
def check_range(value, boundary):
    if any(lower <= value <= upper for (lower, upper) in boundary):
        return 'Yes'
    else:
        return 'No'
   
#Check Time Values here
within_boundary = []    
for i in range(len(df_table)):
    row = df_table.loc[i]
    if row['Code'] in (ranges.keys()):
        
        if any(lower <= row['Timestamp'] <= upper for (lower, upper) in ranges[row['Code']]):
            within_boundary.append('Yes')
        else:
            within_boundary.append('No')
    else:
        within_boundary.append('NaN')
        

df_table['Within_Boundary'] = within_boundary      
print(df_table)

输出:

  Code  Timestamp  Col1  Col2 Within_Boundary
0     A          1     0     0             Yes
1     A          2     1     1             Yes
2     A          3     2     2              No
3     A          4     3     3              No
4     A          5     4     4             Yes
5     A          6     5     5             Yes
6     B          1     6     6             Yes
7     B          2     7     7             Yes
8     B          3     8     8             Yes
9     B          4     9     9              No
10    B          5    10    10              No
11    B          6    11    11              No
12    C          1    12    12             NaN
13    C          2    13    13             NaN
© www.soinside.com 2019 - 2024. All rights reserved.