#python #python-3.x #pandas #dataframe
#python #python-3.x #pandas #фрейм данных
Вопрос:
Скажем, у меня есть список объектов date dates = ['2020-03-01', '2020-05-10']
и фрейм данных, индексированный с помощью объекта datetime :
Набор данных был сгенерирован из другого с использованием методов передискретизации pandas с частотой «1h».
Я хотел бы заполнить значения столбцов A и B, используя список dates
, содержащий объект date. Точнее, если индекс совпадает с днем элемента dates
, я хочу поместить соответствующую строку и все предыдущие строки за 1 месяц с 1 в качестве значений. Остальные строки должны быть заполнены 0 в качестве значений.
Моя стратегия состоит в том, чтобы начать с нулевого фрейма данных, разделяющего столбцы и индекс исходного. Но у меня возникают некоторые проблемы, когда я хочу заполнить значения. На самом деле, я могу сделать это с помощью цикла foor, но я верю в то, что pandas достаточно мощный, чтобы выполнить эту работу с помощью нескольких строк.
Кто-нибудь может мне помочь? Я был бы признателен за любую помощь.
Редактировать: чтобы упростить кодирование / тестирование, я немного изменил формулировку проблемы. Индекс даты и времени теперь равен всем часам 2020-01-01. Приведенный ниже код, похоже, работает хорошо, но я не вижу способа перебирать список дат без цикла for … Вы можете начать с этого. Код :
import pandas as pd
import numpy as np
datetime_index = pd.date_range(start='2020-01-01 00:00:00',
end='2020-01-01 23:59:59', freq='1h')
n_cols = 2
n_rows = datetime_index.size
df_shape =(n_rows, n_cols)
dates = ['2020-01-01 05:00:00']
df = pd.DataFrame(np.random.randint(0,10, size=df_shape),
index = datetime_index.values,
columns = [f'column {i}' for i in range(n_cols)])
data = pd.DataFrame(np.zeros(df_shape).astype(int),
index = datetime_index.values,
columns = [f'column {i}' for i in range(n_cols)])
data['column 0'] = data.apply(lambda x: int(x.name in pd.date_range(
start=pd.to_datetime(dates[0]) - pd.Timedelta(1, unit='hours'),
end=pd.to_datetime(dates[0]),
freq='1h'
)), axis=1)
Комментарии:
1. Вы должны привести пример, над которым люди могут работать.
2. Конечно, минутку, я его предоставлю.
3. @user2640045 Я добавил код для начала, и, похоже, он работает хорошо. Но я не вижу способа перебирать даты без цикла for .
Ответ №1:
Вот немного другая версия:
import pandas as pd
window = 30 # days
targets = ['2020-03-01', '2020-05-10']
dates = pd.date_range(start='2020-01-29', end='2020-07-01', freq='14d')
# create data frame
t = pd.DataFrame(index=dates)
# is target date close to i-th date?
for target in targets:
t[target] = abs((t.index - pd.Timestamp(target)).days) < window
print(t.astype(int))
2020-03-01 2020-05-10
2020-01-29 0 0
2020-02-12 1 0
2020-02-26 1 0
2020-03-11 1 0
2020-03-25 1 0
2020-04-08 0 0
2020-04-22 0 1
2020-05-06 0 1
2020-05-20 0 1
2020-06-03 0 1
2020-06-17 0 0
2020-07-01 0 0
Ответ №2:
Я изменил частоту на две недели, чтобы мне было легче проверить свой результат
import pandas as pd
import numpy as np
from datetime import datetime
datetime_index = pd.date_range(start='2020-01-01 00:00:00',
end='2020-10-01 23:59:59', freq=f'{2*24*7}h')
n_cols = 2
n_rows = datetime_index.size
df_shape =(n_rows, n_cols)
dates = ['2020-03-01', '2020-05-10']
def to_datetime(x):
year, month, day = map(int, x.split("-"))
return datetime(year=year, month=month, day=day)
dates = list(map(to_datetime, dates))
date_series = pd.Series(datetime_index, index=datetime_index)
pd.DataFrame({f"column{i}":date_series
.apply(lambda x:int(-pd.Timedelta(days=30)<(x-dates[i])<pd.Timedelta(days=30)))
for i in range(len(dates))})
это дает
column0 column1
2020-01-01 0 0
2020-01-15 0 0
2020-01-29 0 0
2020-02-12 1 0
2020-02-26 1 0
2020-03-11 1 0
2020-03-25 1 0
2020-04-08 0 0
2020-04-22 0 1
2020-05-06 0 1
2020-05-20 0 1
2020-06-03 0 1
2020-06-17 0 0
2020-07-01 0 0
2020-07-15 0 0
2020-07-29 0 0
2020-08-12 0 0
2020-08-26 0 0
2020-09-09 0 0
2020-09-23 0 0
Комментарии:
1. Ваша работа почти выполнила свою работу. Фактически, в данной строке значения должны быть равны одинаковому и уникальному значению (либо 0, либо 1). Это заставляет меня думать, что нам не нужно много столбцов.. он просто использует память ни для чего интересного.
2. @kakarotto Вы говорите, что хотите объединить логические значения (на которых основаны числа) с amp; ? Вы заставляете меня думать, что вам следует это прочитать pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html или понаблюдайте за этим youtu.be/Pau9An-fQZk :).
3. @user2640045 Я имею в виду, что исходный фрейм данных должен быть скопирован, но его значения должны быть либо 0, либо 1. Если строка имеет индекс, соответствующий одной из дат в списке, для нее должно быть задано значение 1, а для всех предыдущих строк по 1 единице также должно быть задано значение 1 (где единица изначально равна месяцу, но это не имеет значения, поскольку это не меняет процесс). В любом случае, спасибо, что ваш ответ с ответом jsmart помог мне решить мою проблему. Спасибо, ребята.