Eu tenho um dataframe python df_A cuja coluna de índice contém dados inteiros e representa um carimbo de data / hora na linha de segundos (pode não ter um gradiente estritamente monotônico).
E eu tenho outro dataframe df_B que contém apenas um conjunto de dados. Uma de suas "células" me dá um horário de início. Meu objetivo é pegar esse horário de início do df_B, colocá-lo na primeira linha de uma nova coluna a ser criada no df_A e iniciar um cálculo a partir daí com base na linha do índice.
A coluna de índice de df_A contém números inteiros como este:
Int64Index([ 2374, 2376, 2377, 2378, 2379, 2380, 2381, 2383, 2384,
2385,
...
10531, 10532, 10533, 10535, 10536, 10537, 10538, 10539, 10540,
10541],
dtype='int64', name='TimePeak', length=7107)
df_B fica assim:
df_B = pd.DataFrame([['2021-07-08T08:56:46.637', 590, 0, 4270.29]], columns=['BeginTime', 'Altitude', 'Status', 'Duration'])
Primeiro, obtenho meu valor de tempo inicial por df_B: Para cálculos adicionais, preciso que a entrada do tipo string "BeginTime" seja compatível com números inteiros de df_B.index. É por isso que converto tudo para o formato data e hora:
# Gain the first entry of the new dataframe column 'time'
df_A['time'].iloc[0] = pd.to_datetime(df_B.BeginTime)
Mas a primeira entrada não é colocada na primeira linha da nova coluna, pois produz uma mensagem ValueError: Could not convert object to NumPy datetime
Não entendo por que não foi convertida. Devo definir seu conteúdo mais especificamente? Outros valores de data e hora deste formato são convertidos sem qualquer mensagem de erro para o formato AAAA-MM-DD hh:mm:ss.sss (sem o "T" no meio)
Então eu calcularia o tempo delta:
# calculate timedelta according to the index column values starting in the second
# row as the first row has no reference to be calculated from
for i in range(1, len(df_A)):
df_A['deltaT'][i] = df_A.index[i] - df_A.index[i-1]
Isso me dá um erro importante para deltaT. Por que?
Posso definir uma coluna vazia primeiro:
df_A['deltaT'] = pd.to_timedelta(pd.Series(dtype='float'), unit='s')
for i in range(1, len(df_A)):
df_A['deltaT'][i] = df_A.index[i] - df_A.index[i-1]
Mas isso terminaria em uma série de advertências:
See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
df_A['deltaT'][i] = df_A.index[i] - df_A.index[i-1]
O que eu poderia suprimir:
pd.options.mode.chained_assignment = None
mas acho que o problema principal está localizado em algum lugar acima do código... (?)
Depois eu calcularia as linhas adicionais com base na diferença deltaT por duas linhas consecutivas:
# calculate the further rows
for i in range (1, len(df_A)):
df_A[i,'time'] = df_A.iloc[i-1]['time'] + pd.to_timedelta(df_A.iloc[i]['deltaT'](1, unit='s'))
df_A['time']
Mas este cálculo também não será realizado.
O código completo:
import pandas as pd
import numpy as np
# df_B:
df_B = pd.DataFrame([['2021-07-08T08:56:46.637', 590, 0, 4270.29]], columns=['BeginTime', 'Altitude', 'Status', 'Duration'])
# df_A
df_A = pd.DataFrame([[2374, 4.5],[2376, 5.7],[2377,23.0],[2378,9.2],[2379,18.7],[2380,10.4],[2381,12.2],[2383,23.9],[2384,21.6],
[2385, 12.1]], columns=['TimePeak', 'data'])
df_A.set_index('TimePeak') # indeed, the index is set earlier due to a merge of several *.csv files
# Gain the first entry of the new dataframe column 'time' and convert it to timedate format
df_A['time'].iloc[0] = pd.to_datetime(df_B.BeginTime)
# calculate timedelta according to the index column values starting in the second
# row as the first row has no reference to be calculated from
for i in range(1, len(df_A)):
df_A['deltaT'][i] = df_A.index[i] - df_A.index[i-1]
# calculate the further rows
for i in range (1, len(df_A)):
df_A[i,'time'] = df_A.iloc[i-1]['time'] + pd.to_timedelta(df_A.iloc[i]['deltaT'](1, unit='s'))
df_A['time']
Também tentei redefinir o índice, mas não funcionou. Alguma dica para eu entender onde fui enganado?
A saída final deve ficar assim:
A lógica exata não é clara, mas é quase certo que você não precisa de um loop.
Se bem entendi, você deseja iniciar o tempo com o valor a partir de
df_B
então incrementar 1s para cada linha. Então usedate_range
:Ou, mais próximo da sua abordagem original, se quiser usar o índice como referência:
Saída: