#python #pandas
Вопрос:
У меня есть огромный фрейм данных pandas (на самом деле имеет 5 строк):
df = pd.DataFrame({'id': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
'opn1': [20180301, 20180401, 20180501, 20180601, 20180701, 20180801, 20180901, 20181001, 20181101, 20181201],
'opn2': [20180401, 20180501, 20180601, 20180701, 20180801, 20180901, 20181001, 20181101, 20181201, 20190101],
'opn3': [20180501, 20180601, 20180701, 20180801, 20180901, 20181001, 20181101, 20181201, 20190101, 20190201],
'opn4': [20180601, 20180701, 20180801, 20180901, 20181001, 20181101, 20181201, 20190101, 20190201, 20190301],
'opn5': [20180701, 20180801, 20180901, 20181001, 20181101, 20181201, 20190101, 20190201, 20190301, 20190401],
'cls1': [0, 20180520, 0, 0, 0, 0, 0, 0, 0, 0],
'cls2': [0, 0, 0, 0, 20181031, 0, 0, 0, 0, 0],
'cls3': [0, 0, 20180725, 0, 20180701, 0, 0, 0, 0, 0],
'cls4': [0, 0, 0, 0, 0, 0, 20190101, 0, 0, 0],
'cls5': [0, 20180731, 0, 0, 0, 0, 0, 0, 0, 20190510],
})
Мое требование состоит в том, чтобы создать флаг со значением 1, если какая-либо из дат закрытия cls1..5
opn1..5
Пример вывода: для id==2, cls5
Я хочу избежать цикла и запустить его как можно быстрее. В моих данных ~5 млн строк.
Возможно np.where
, с помощью комбинации any
?
Комментарии:
1. вы можете добавить свой образец вывода?
2. идентификаторы 2 и 5 должны быть помечены как 1
3. Использование 0 в качестве отсутствующего значения кажется хуже, чем использование NaN. (это экономит память, но будет работать медленнее).
4. в моих данных уже есть нули.
5. Проведите сравнительный анализ производительности, чтобы сравнить решения. Мои тесты с использованием %%времени показывают, что мое решение является самым быстрым среди 3 решений, использующих данные выборки (мое решение 0,9 мс, в то время как другие решения составляют 1,4 мс, 3.x мс). Сейчас немного занят, поэтому не могу показать вам результаты сравнительного анализа.
Ответ №1:
Вы можете попробовать использовать np.any
с axis=0
. Сначала создайте условие, а затем примените его к соответствующим столбцам:
cond = lambda i: ((df['cls' str(i)] != 0) amp; (df['cls' str(i)] < df['opn' str(i)])).values
df['flag'] = np.any([cond(i) for i in range(1,6)], axis=0).astype(int)
Это пометит строки с id=2
и id=5
.
Ответ №2:
Вы можете использовать .filter
для фильтрации столбцов 2 части для сравнения. Затем используйте any
дальше axis=1
, как показано ниже:
df['flag'] = ( ((df.filter(like='cls').values != 0) amp;
(df.filter(like='cls').values < df.filter(like='opn').values)
)
.any(axis=1)
.astype(int)
)
Результат:
id
2 и 5 помечены.
print(df)
id opn1 opn2 opn3 opn4 opn5 cls1 cls2 cls3 cls4 cls5 flag
0 1 20180301 20180401 20180501 20180601 20180701 0 0 0 0 0 0
1 2 20180401 20180501 20180601 20180701 20180801 20180520 0 0 0 20180731 1
2 3 20180501 20180601 20180701 20180801 20180901 0 0 20180725 0 0 0
3 4 20180601 20180701 20180801 20180901 20181001 0 0 0 0 0 0
4 5 20180701 20180801 20180901 20181001 20181101 0 20181031 20180701 0 0 1
5 6 20180801 20180901 20181001 20181101 20181201 0 0 0 0 0 0
6 7 20180901 20181001 20181101 20181201 20190101 0 0 0 20190101 0 0
7 8 20181001 20181101 20181201 20190101 20190201 0 0 0 0 0 0
8 9 20181101 20181201 20190101 20190201 20190301 0 0 0 0 0 0
9 10 20181201 20190101 20190201 20190301 20190401 0 0 0 0 20190510 0
Ответ №3:
вот еще одна версия, в которой вы перебираете возможные комбинации открытия и закрытия:
df['flag'] = False
for i in range(1,6):
df['flag'] = df['flag'] | (df[f'cls{i}'] < df[f'opn{i}']) amp; (df[f'cls{i}'] != 0)