#python #pandas
Вопрос:
Мне нужно создать столбец индикатора на основе dfmap
диапазонов дат для всех тегов в df
.
import pandas as pd
df = pd.DataFrame({
'date': ['2019-04-19','2019-04-20','2019-04-21', '2019-04-22',
'2019-10-01','2019-10-02','2019-10-03', '2019-10-04'],
'tag': ['ID F', 'ID F', 'ID F', 'ID F',
'ID B', 'ID B', 'ID B', 'ID B'],
'value': ['1', '2', '3', '4',
'1', '3', '5', '7']})
df['date'] = pd.to_datetime(df['date'], infer_datetime_format=True)
dfmap = pd.DataFrame({
'start_date': ['2019-04-20','2019-10-03'],
'end_date': ['2019-04-21','2019-10-04'],
'tag': ['ID F', 'ID B']})
print(df)
print(dfmap)
date tag value
0 2019-04-19 ID F 1
1 2019-04-20 ID F 2
2 2019-04-21 ID F 3
3 2019-04-22 ID F 4
4 2019-10-01 ID B 1
5 2019-10-02 ID B 3
6 2019-10-03 ID B 5
7 2019-10-04 ID B 7
start_date end_date tag
0 2019-04-20 2019-04-21 ID F
1 2019-10-03 2019-10-04 ID B
Желаемый кадр Данных:
print(desired_df)
date tag value indicator
0 2019-04-19 ID F 1 0
1 2019-04-20 ID F 2 1
2 2019-04-21 ID F 3 1
3 2019-04-22 ID F 4 0
4 2019-10-01 ID B 1 0
5 2019-10-02 ID B 3 0
6 2019-10-03 ID B 5 1
7 2019-10-04 ID B 7 1
Комментарии:
1. Каковы условия для установки индикатора de на 0 или 1 в зависимости от
dfmap
?2. сам диапазон дат
Ответ №1:
Просто написав простую логику:
g = lambda x: pd.to_datetime(x)
g = lambda x: pd.to_datetime(x)
df['date'] = g(df['date'])
dfmap[['start_date', 'end_date']].apply(g)
conditions = [((df['tag'].eq(idx)) amp; (df['date'].between(start, end))) for idx, start, end in zip(dfmap['tag'], dfmap['start_date'], dfmap['end_date'])]
cond = conditions[0] | conditions[1]
df['indicator'] = np.where(cond,1,0)
df:
date tag value indicator
0 2019-04-19 ID F 1 0
1 2019-04-20 ID F 2 1
2 2019-04-21 ID F 3 1
3 2019-04-22 ID F 4 0
4 2019-10-01 ID B 1 0
5 2019-10-02 ID B 3 0
6 2019-10-03 ID B 5 1
7 2019-10-04 ID B 7 1
Ответ №2:
Полная логика того, как дата и метка идентифицируют индикатор, мне неясна. Я решил, что это будет
- если диапазон существует
- проверьте, совпадает ли тег
- если диапазон и метка совпадают, индикатор равен 1
- индикатор else равен 0
Мне нравится писать функции, когда я сталкиваюсь с такого рода проблемами.
# first setup the dfmap to explicitly be Timestamp as you did with df
dfmap['start_date'] = pd.to_datetime(dfmap['start_date'])
dfmap['end_date'] = pd.to_datetime(dfmap['end_date'])
# write your logic for the range indicators
def get_indicator(row, df):
dt = row.date
tag = row.tag
for idx, map_row in df.iterrows():
if map_row.start_date <= dt <= map_row.end_date:
if row.tag == map_row.tag:
return 1
return 0
# apply
df['indicator'] = df.apply(lambda x: get_indicator(x, dfmap), axis=1)
# print(df)
# date tag value indicator
# 0 2019-04-19 ID F 1 0
# 1 2019-04-20 ID F 2 1
# 2 2019-04-21 ID F 3 1
# 3 2019-04-22 ID F 4 0
# 4 2019-10-01 ID B 1 0
# 5 2019-10-02 ID B 3 0
# 6 2019-10-03 ID B 5 1
# 7 2019-10-04 ID B 7 1
Ответ №3:
попробуйте использовать date_range()
agg()
метод и isin()
astype()
метод:
s=dfmap.agg(lambda x:pd.date_range(x['start_date'],x['end_date']).normalize(),axis=1).explode().unique()
df['indicator']=df['date'].isin(s).astype(int)
Примечание: вы также можете использовать apply()
вместо agg()
метода
или
через date_range(
) zip()
s=[[*pd.date_range(x,y).normalize()] for x,y in zip(dfmap['start_date'],dfmap['end_date'])]
s=pd.Series(s).explode().unique()
df['indicator']=df['date'].isin(s).view('i1')
выход из df
:
date tag value indicator
0 2019-04-19 ID F 1 0
1 2019-04-20 ID F 2 1
2 2019-04-21 ID F 3 1
3 2019-04-22 ID F 4 0
4 2019-10-01 ID B 1 0
5 2019-10-02 ID B 3 0
6 2019-10-03 ID B 5 1
7 2019-10-04 ID B 7 1
Комментарии:
1. Похоже, что это создает индикатор на каждом гггг-мм-дд чч:мм:сс отметка времени, где 00:00:00, так что один раз в 24 часа
2. @Starbucks это зависит от ваших дат, кстати, dfmap