Я хочу создать вложенный словарь даты и времени, где первый уровень ключей - это годы, а второй - месяцы.

avatar
Question Asker and Answerer
8 августа 2021 в 19:33
54
1
0

У меня есть набор данных, который содержит строковые объекты, плавающий тип и даты, подобные следующим:

----------------------------------------------
|str obj col.| Int. Col | Float Col| Date Col|
----------------------------------------------
| str obj.   | Int.     |   Float  | Date Obj|                              
|---------------------------------------------
| str obj.   | Int.     |   Float  | Date Obj|
|---------------------------------------------
| str obj.   | Int.     |   Float  | Date Obj|
----------------------------------------------
|      .     |    .     |     .    |    .    |
----------------------------------------------
|      .     |    .     |     .    |    .    |
----------------------------------------------
|      .     |    .     |     .    |    .    |
----------------------------------------------
| str obj.   |  Int.    |   Float  | Date Obj|
----------------------------------------------

Объекты даты имеют формат мм/дд/гггг. Я смог сгруппировать даты по месяцам года, используя pandas. Я достиг этого, создав два списка. Один список содержит все метки месяца года в виде строк, другой содержит список фреймов данных. Я объединил их в словарь, содержащий список DataFrames. Я достиг этого, используя следующее:

L2  = sorted(set(df['Date'].dt.strftime('%Y-%m').tolist()))
L3 = df.groupby(pd.Grouper(key='Date', freq='M'))
Dict_2 = dict(zip(L2, L3))

Затем я создал пустой словарь, содержащий только годы. Итак, для создания этого я использовал следующее:

L1 = sorted(set(df['Date'].dt.strftime('%Y').tolist()))
Dict_1 = dict.fromkeys(L1)

Цель состоит в том, чтобы объединить Dict_1 и Dict_2 в словарь, классифицированный по годам, а затем по месяцам. Для достижения этой цели я использовал следующее:

for year in Dict_1.keys():
    for month_year in Dict_2.keys():
        if search(str(year), str(month_year)):
           Dict_1[year].update({month_year, Dict_2[month_year]})

Причина этого заключалась в том, что если строка года совпадала со строкой month_year, то этот новый подраздел добавлялся в Dict_1.

Ожидаемый результат:

Dict_1 = {'2008': {'2008-01': [DataFrame Obj], '2008-02':[DataFrame Obj],... '2008-12':[DataFrame Obj]}, ...  '2019': {'2019-01': [DataFrame Obj], '2019-02':[DataFrame Obj],... '2019-12':[DataFrame Obj]}}

Однако я получил следующую ошибку:

AttributeError: 'NoneType' object has no attribute 'update'

Я думал, что этот метод спонтанно сгенерирует подразделы и заменит значение none, содержащееся внутри этого ключа словаря, но он этого не делает. Что приводит меня к следующим трем вопросам:

Во-первых, как я могу добавить этот подраздел из Dict_2 в этот пустой ключ в Dict_1? Во-вторых, как я могу добавить исходную информацию, содержащуюся в моем подразделе Dict_2, в мой ключ Dict_1? Наконец, есть ли лучший способ сделать это, кроме использования моего текущего метода? Возможно, понимание словаря или какая-то векторизованная операция в пандах?

Цель состоит в том, чтобы иметь словарь, в котором есть годы, затем месяц-год, а затем список объектов DataFrame.

Источник

Ответы (1)

avatar
gr8t1
9 августа 2021 в 00:43
1

Только обращение к циклу for

Мне не удалось полностью воспроизвести то, что вы делаете. Предполагая, что ваш шаг до цикла for возвращает правильный вывод, это должно работать:

for year in L1:
    months_dfs_in_year = []
    for month_year, df_obj in Dict_2.items():
        if search(year, month_year):
            months_dfs_in_year.append((month_year, df_obj))
            Dict_1[year] = dict(months_dfs_in_year)

Примечание: Обычно вы должны перебирать что-то и вносить в него изменения. Поэтому я заменил Dict_1.keys() на L1 (которое я бы назвал более описательным, например, «годы»).

Чтобы объяснить, вот ваш код

for year in Dict_1.keys():
    for month_year in Dict_2.keys():
        if search(str(year), str(month_year)):
           Dict_1[year].update({month_year, Dict_2[month_year]})

Что я добавил/изменил

  • Я удалил str() около года и month_year в search(), они уже должны быть строками. Показалось ненужным, если нужно, добавим обратно.

  • Без списка months_dfs_in_year конечным результатом будет только последняя пара month_year: [dataframe].

    • вывод для каждого ключа год будет примерно таким:

        {'2008': {'2008-12': [dataframe]}, '2009': {'2009-12': [dataframe]}, ...}
      
  • Список находится в цикле после for year in L1, поэтому он "сбрасывается" для каждого year в L1. В противном случае мы получим что-то вроде:

    {'2008': {'2008-01': [dataframe], ...  '2008-12': [dataframe]}, 
     '2009': {'2008-01': [dataframe], ...  '2009-12': [dataframe]}, 
     '2010': {'2008-01': [dataframe], ...  '2010-12': [dataframe]}}
    

A словопонимание версия:

И, главным образом, потому, что я написал это первым, но на случай, если вы/кто-то еще может найти это полезным.

При этом вам не нужно будет создавать список или "предварительно создавать" Dict_1.

Dict_1 = {year: {month_year: df_obj
                 for month_year, df_obj in Dict_2.items() if search(year, month_year)
                 }
          for year in L1
          }

Question Asker and Answerer
9 августа 2021 в 01:04
1

Я решил проблему, используя решение, похожее на версию понимания словаря. Мое решение было следующим: new_dict = {y_key {m_key: month_obj[m_key] for m_key in month_obj if search(str(y_key), str(m_key))} for y_key in year_obj} Мне не нужно было обращаться к ключам. Почему вы обращаетесь к ключам в этом конкретном случае?

gr8t1
9 августа 2021 в 01:09
0

Спасибо, что указали на это, я случайно оставил это там - изначально у меня был Dict_1 вместо L1 в понимании словаря.