У меня есть словарь, который отображает определенный час (выбранный из дат) на конкретное число.

time_of_day_mapping = {
    4: 0, 5: 0, 6: 0, 7: 0, 8: 0, 9: 0, 10: 0, 11: 0,
    12: 1, 13: 1, 14: 1, 15: 1, 16: 1,
    17: 2, 18: 2, 19: 2, 20: 2, 21: 2, 22: 2, 23: 2,
    0: 3, 1: 3, 2: 3, 3: 3}

Меня огорчает, что некоторые значения отображаются на одинаковые значения, например 0, 1, 2 и 3 отображаются на 3. Я думал об изменении формата ключей словаря на диапазон или кортежи, чтобы избежать повторения таким образом:

time_of_day_mapping = {
    range(4, 12): 0,
    range(12, 17): 1,
    range(17, 24): 2,
    range(0, 4): 3}

Но тогда я не уверен, как эффективно получить отображение с диапазонами в качестве ключей, если у меня есть только одно значение для этого, например:

df['some_date'].apply(lambda x: time_of_day_mapping.get(x.hour)

Я был бы рад получить совет. А может, с точки зрения эффективности, лучше ничего не менять в формате словаря?

-1
dark_matter88 27 Июн 2019 в 13:12

4 ответа

Лучший ответ

Если вас больше всего беспокоит читаемость кода, вы можете определить свой dict так же, как вы, но затем «распаковать» его в исходную форму (чтобы вы могли регулярно выполнять поиск по словарю):

time_of_day_mapping = {
    range(4, 12): 0,
    range(12, 17): 1,
    range(17, 24): 2,
    range(0, 4): 3
}

time_of_day_mapping = dict((key, value) for range_obj, value in time_of_day_mapping.items() for key in list(range_obj))

print(time_of_day_mapping)

После запуска этого кода time_of_day_mapping именно таков, как он впервые появился в вашем вопросе.

И позвольте мне предложить, для повышения читабельности, вы используете начальные кортежи включительно в качестве ключей, а затем range их в понимании, например так:

time_of_day_mapping = {
    (4, 11): 0,
    (12, 16): 1,
    (17, 23): 2,
    (0, 3): 3
}

time_of_day_mapping = dict((key, value) for (start, end), value in time_of_day_mapping.items() for key in list(range(start, end+1)))

print(time_of_day_mapping)

Я думаю, что лучше видеть (4,11):0, а не (4,12):0, когда d[12] != 0.

0
Adam.Er8 27 Июн 2019 в 10:29

Со списком понимания вы можете сделать следующее:

from datetime import datetime
import pandas as pd

time_of_day_mapping = {range(4, 12): 0, range(12, 17): 1, range(17, 24): 2, range(0, 4): 3}

df = pd.DataFrame([datetime(2019,6,25,4,0,0), datetime(2019,6,25,12,0,0), datetime(2019,6,25,17,0,0), datetime(2019,6,25,2,0,0)], columns = ["some_date"])
df['my_new_col'] = df['some_date'].apply(lambda x: [time_of_day_mapping[key] for key in time_of_day_mapping if x.hour in key][0])

print(df)

< Сильный > Выход

+----+----------------------+------------+
|    |      some_date       | my_new_col |
+----+----------------------+------------+
| 0  | 2019-06-25 04:00:00  |          0 |
| 1  | 2019-06-25 12:00:00  |          1 |
| 2  | 2019-06-25 17:00:00  |          2 |
| 3  | 2019-06-25 02:00:00  |          3 |
+----+----------------------+------------+
0
Sebastien D 27 Июн 2019 в 10:27

Вы можете использовать tuple вместо диапазона и просто искать значение часа в вашем dict

Типа того:

from random import randint
import datetime

#use tuple instead of range
time_of_day_mapping = {
    (4, 5, 6, 7, 8, 9, 10, 11): 0,
    (12, 13, 14, 15, 16): 1,
    (17, 18, 19, 20, 21, 22, 23): 2,
    (0, 1, 2, 3): 3}

# here I created a list of random datetimes
dates = []
for i in range(0,10):
    date=datetime.datetime(randint(2005,2025), randint(1,12),randint(1,28),randint(1,23),randint(0,59))
    dates.append(date.hour)
print(dates)

res = [time_of_day_mapping[k] for d in dates for k in time_of_day_mapping if d in k]
print(res)
0
alireza yazdandoost 27 Июн 2019 в 10:55

Вы ищете либо двунаправленную карту, либо карту ключей для коллекций.

Первое можно сделать с помощью bidict.

from bidict import bidict                                                                                                                                                                     

d = bidict([('a', 23), ('b', 42)])                                                                                                                                                            

d.inverse[23] # 'a'

Последнее может быть достигнуто с помощью defaultdict.

from collections import defaultdict                                                                                                                                                           

d = defaultdict(list)
d['a'].append(23)                                                                                                                                                                             
d['a'].append(42)                                                                                                                                                                             
d['a'] # [23, 42]    
0
Markus Rother 27 Июн 2019 в 10:42