Данные:
# Sample data
data = {
'Start Date': ['2022-10-18', '2022-10-25', '2023-04-17'],
'End Date': ['2022-10-20', '2023-04-06', '2023-07-04'],
'Close1': [17486.95, 17656.35, 17706.85],
'Close2': [17563.95, 17599.15, 19389.00],
'NF_BEES1': [0.58, 0.19, 0.12],
'NF_BEES2': [0.63, 0.75, 0.73],
'Difference': [77.00, -57.20, 1682.15],
'Days Difference': [2, 163, 78]
}
# Create DataFrame
df = pd.DataFrame(data)
df
# Convert date columns to datetime
df['Start Date'] = pd.to_datetime(df['Start Date'])
df['End Date'] = pd.to_datetime(df['End Date'])
Выход:
Start Date End Date Close1 Close2 NF_BEES1 NF_BEES2 Difference Days Difference
0 2022-10-18 2022-10-20 17486.95 17563.95 0.58 0.63 77.00 2
1 2022-10-25 2023-04-06 17656.35 17599.15 0.19 0.75 -57.20 163
2 2023-04-17 2023-07-04 17706.85 19389.00 0.12 0.73 1682.15 78
Если столбец Days Difference
> 8, то создайте новую строку в df, и End Date
предыдущей строки должно быть Start Date
в новой строке, а Start Date
текущей строки (разница в днях > 8) должно быть End Date
.
Значения Close1
, Close2
, NF_BEES1
, NF_BEES2
также следует изменить, например Start Date
и End Date
. Исходя из этого, необходимо рассчитать Days Difference
для новой строки.
Мой код (не работает должным образом):
# Iterate through the DataFrame
for idx, row in df.iterrows():
rows.append(row)
if row['Days Difference'] > 8:
# Create a new row
new_row = row.copy()
new_row['Start Date'] = rows[-2]['End Date']
new_row['Close1'] = rows[-2]['Close2']
new_row['NF_BEES1'] = rows[-2]['NF_BEES2']
new_row['End Date'] = row['Start Date']
new_row['Close2'] = row['Close1']
new_row['NF_BEES2'] = row['NF_BEES1']
new_row['Difference'] = (new_row['Close2'] - new_row['Close1'])
new_row['Days Difference'] = (new_row['End Date'] - new_row['Start Date']).days
print(new_row)
print(type(new_row))
# Create a new DataFrame with the split rows
new_df = pd.DataFrame(rows)
new_df
Мой результат:
Start Date End Date Close1 Close2 NF_BEES1 NF_BEES2 Difference Days Difference
0 2022-10-18 2022-10-20 17486.95 17563.95 0.58 0.63 77.00 2
1 2022-10-25 2023-04-06 17656.35 17599.15 0.19 0.75 -57.20 163
2 2023-04-17 2023-07-04 17706.85 19389.00 0.12 0.73 1682.15 78
Ожидаемый результат:
Start Date End Date Close1 Close2 NF_BEES1 NF_BEES2 Difference Days Difference
18 2022-10-18 2022-10-20 17486.95 17563.95 0.58 0.63 77.00 2
19 2022-10-20 2022-10-25 17563.95 17656.35 0.63 0.19 93 5
20 2023-04-06 2023-04-17 17599.15 17706.85 0.75 0.12 107 11
Добавлена информация в запрос. Спасибо @mozway, @e-motta!!
IIUC, используйте маску, копию End и сдвиг:
# identify rows to change
m = df['Days Difference'].gt(8)
# keep a copy of the previous End
prev_end = df['End Date'].shift()
# update the rows
df.loc[m, 'End Date'] = df['Start Date']
df.loc[m, 'Start Date'] = prev_end
Выход:
Start Date End Date Close1 Close2 NF_BEES1 NF_BEES2 Difference Days Difference
0 2022-10-18 2022-10-20 17486.95 17563.95 0.58 0.63 77.00 2
1 2022-10-20 2022-10-25 17656.35 17599.15 0.19 0.75 -57.20 163
2 2023-04-06 2023-04-17 17706.85 19389.00 0.12 0.73 1682.15 78
Если вам нужен новый DataFrame в качестве вывода, просто сделайте то же самое с копией, а если вы хотите обновить несколько столбцов, примените shift
ко всем сразу и обновите различия, а затем выполните вычитание (и преобразуйте в дней, когда нужный):
# make a copy
new_df = df.copy()
# shift the columns
m = df['Days Difference'].gt(8)
new_df.loc[m, ['End Date', 'Close2', 'NF_BEES2']] = df[['Start Date', 'Close1', 'NF_BEES1']][m].values
new_df.loc[m, ['Start Date', 'Close1', 'NF_BEES1']] = df[['End Date', 'Close2', 'NF_BEES2']].shift()[m].values
# update the differences
new_df['Difference'] = new_df['Close2'].sub(new_df['Close1'])
new_df['Days Difference'] = new_df['End Date'].sub(new_df['Start Date']).dt.days
Выход:
Start Date End Date Close1 Close2 NF_BEES1 NF_BEES2 Difference Days Difference
0 2022-10-18 2022-10-20 17486.95 17563.95 0.58 0.63 77.0 2
1 2022-10-20 2022-10-25 17563.95 17656.35 0.63 0.19 92.4 5
2 2023-04-06 2023-04-17 17599.15 17706.85 0.75 0.12 107.7 11
IIUC, вам также потребуется изменить столбцы 'Close...'
и 'NF_BEES...'
.
@e-motta, конечно, это та же логика, хотя в вопросе это не объяснено.
Правда, я сделал это из названия и ожидаемого результата, но в самом вопросе об этом не упоминается.
@e-motta Я добавил полную логику, попрошу ОП разъяснить это
Предполагая, что ваши столбцы отсортированы в определенном порядке 'Start Date', 'End Date', 'Close1', 'Close2', 'NF_BEES1', 'NF_BEES2'
, вы можете использовать shift
условно так:
out = df.copy()
mask = df["End Date"] - df["Start Date"] > pd.Timedelta(days=8)
out.loc[mask, ["Start Date", "Close1", "NF_BEES1"]] = df.shift().shift(-1, axis=1)
out.loc[mask, ["End Date", "Close2", "NF_BEES2"]] = df.shift(axis=1)
out["Difference"] = out["Close2"] - out["Close1"]
out["Days Difference"] = (out["End Date"] - out["Start Date"]).dt.days
Start Date End Date Close1 Close2 NF_BEES1 NF_BEES2 Difference Days Difference
0 2022-10-18 2022-10-20 17486.95 17563.95 0.58 0.63 77.0 2
1 2022-10-20 2022-10-25 17563.95 17656.35 0.63 0.19 92.4 5
2 2023-04-06 2023-04-17 17599.15 17706.85 0.75 0.12 107.7 11
со многими shift
кажется немного сложным, не так ли? ;)
@mozway Возможно, да, но я не мог придумать ничего проще. :-)
Это хороший способ сделать его кратким, но вам следует просто упомянуть, что для этого необходимо, чтобы столбцы были отсортированы в определенном порядке A1/A2/B1/B2/C1/C2, иначе это приведет к путанице значений.
@mozway Хорошая мысль, я добавил комментарий по этому поводу.
В своем вопросе вы не упомянули судьбу Close/NF_BEES/Difference. Хотя это можно сделать из вывода, лучше отредактируйте вопрос, чтобы он был явным;)