Как векторизовать (используя Numpy / Pandas) мой вложенный оператор if во вложенном цикле for - PullRequest
1 голос
/ 13 апреля 2020

Я пытаюсь сравнить два DataFrames, я буду sh, чтобы эффективно использовать pandas (or numpy) вместо вложенного для l oop с оператором if в нем для решения конкретной проблемы. Ниже приведен небольшой фрагмент моей программы.

spindleload = {'time': ['2020-02-03 00:18:07', '2020-02-03 00:18:08', '2020-02-03 00:18:09', '2020-02-03 00:18:10', '2020-02-03 00:18:11', '2020-02-03 00:18:12', '2020-02-03 00:18:13', '2020-02-03 00:18:14', '2020-02-03 00:18:15', '2020-02-03 00:18:16', '2020-02-03 00:18:17'], 
               'value': [17,25,14,14,22,22,22,22,22,12,19]}
df1 = pd.DataFrame(data=spindleload) 


cycletime = {'newtimestart': ['2020-02-03 00:18:08','2020-02-03 00:18:13'], 'newtimeend': ['2020-02-03 00:18:11', '2020-02-03 00:18:15']}
df2 = pd.DataFrame(data=cycletime)

Теперь я получу sh до l oop, чтобы получить время и значение в df1 для соответствующих значений между newtimestart и newtimeend in df2 . Ниже приведен код.

output_graph_time = []
output_graph_value = []

for i in range(len(df2)):
    for j in range(len(df1)):
        if df1['time'][j] >= df2['newtimestart'][i]:
            output_graph_time.append(df1['time'][j])
            output_graph_value.append(df1['value'][j])  
            if df1['time'][j] == df2['newtimeend'][i]:
                break
print(output_graph_time)
print(output_graph_value)

Теперь здесь код работает нормально, но когда он читает миллионы строк данных, которые он не может выполнить, я также пытался реализовать Numba, но ядро ​​не смогло обрабатывать и перезапускать. Поэтому я прошу решить эту проблему, используя Numpy или Pandas метод векторизации .

В дополнение к этому, когда я попытался применить метод векторизации, я обнаружил трудности в нарушение условия после каждого выполнения.

Ответы [ 2 ]

0 голосов
/ 13 апреля 2020

Я понимаю, что df1 - это несколько миллионов строк. Если ваш df2 не слишком большой, вы можете сделать кросс-слияние:

(df1.assign(dummy=1)
    .merge(df2.assign(dummy=1), on='dummy')
    .query('newtimestart<=time<=newtimeend')
)

Вывод:

                   time  value
2   2020-02-03 00:18:08     25
4   2020-02-03 00:18:09     14
6   2020-02-03 00:18:10     14
8   2020-02-03 00:18:11     22
13  2020-02-03 00:18:13     22
15  2020-02-03 00:18:14     22
17  2020-02-03 00:18:15     22
0 голосов
/ 13 апреля 2020

Вы можете преобразовать df2 в диапазон дат и разбить его, затем использовать isin filter df1.

Преобразовать в дату и время из строк ( Игнорировать этот шаг, если значения уже являются datetime )

df1['time'] = pd.to_datetime(df1['time'])
df2 = df2.apply(pd.to_datetime)

Отобразить как pd.date_range и explode, затем отфильтровать, используя isin

out = (df1[df1['time'].isin(df2.agg(tuple,1).map(lambda x: 
                  pd.date_range(*x,freq='s')).explode())])

print(out)

                 time  value
1 2020-02-03 00:18:08     25
2 2020-02-03 00:18:09     14
3 2020-02-03 00:18:10     14
4 2020-02-03 00:18:11     22
6 2020-02-03 00:18:13     22
7 2020-02-03 00:18:14     22
8 2020-02-03 00:18:15     22

Что похоже на ваш вывод:

print(output_graph_time)
print(output_graph_value)

['2020-02-03 00:18:08', '2020-02-03 00:18:09', '2020-02-03 00:18:10', 
'2020-02-03 00:18:11', '2020-02-03 00:18:13', '2020-02-03 00:18:14', 
 '2020-02-03 00:18:15']

[25, 14, 14, 22, 22, 22, 22]
...