Заполните значения в соответствии с данными даты в другом df в python - PullRequest
0 голосов
/ 30 октября 2019

Я хотел бы добавить дополнительную информацию из df2 в df1, сопоставляя данные даты.

df1 - основной фрейм данных:

            x0      x1      x2      x3      x4      x5      ...  x10000  Date       
1           40      31.05   25.5    25.5    25.5    25      ...    33    2013-11-13
2           35      35.75   36.5    36.5    36.5    36.5    ...    29    2013-09-05
⋮           ⋮       ⋮        ⋮       ⋮       ⋮        ⋮               ⋮

df2 - дополнительная информация о погоде, которую я хочу добавить к df1:

year month day  maxtemp mintemp rainfall    wind 
2013    1   1   26.2    20.2     0          32.4
2013    1   2   22.9    20.3     0          10
2013    1   3   24.8    18.4     0          28.8
2013    1   4   26.6    18.3     0          33.5
2013    1   5   28.3    20.9     0          33.4
2013    1   6   28      21.6     0          32.8
2013    1   7   27.5    21.4     0          26.8
2013    1   8   42.3    20.9     0          25.5
2013    1   9   25      21.1     0          20.9
2013    1   10  25.4    20.2     0          14
⋮       ⋮    ⋮   ⋮        ⋮        ⋮           ⋮

Мне нужно добавить предыдущие 100 днейиз maxtemp, mintemp, rainfall и wind данных, извлеченных из df2, до конца каждой строки в df1 по горизонтали , путем сопоставления с year, monthday из Date в df1. Таким образом, Date - это сотый день, а предыдущие 99 дней - это 99 дней до Date.

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

     x0  x1    x2   x3   x4   x5   ... x10000 Date       max_t1...max_t100 min_t1...min_t100 rf1... rf100 w1 ... w100
1    40  31.05 25.5 25.5 25.5 25   ...  33    2013-01-01 26.2  ...         20.2  ...          0 ...       32.4...  
2    35  35.75 36.5 36.5 36.5 36.5 ...  29    2013-01-03 24.8. ...         18.4  ...          0 ...       28.8
⋮     ⋮   ⋮      ⋮    ⋮    ⋮     ⋮          ⋮

где

max_t1, ..., max_t100 represent max temperature from day1 to day100(`Date` day);
min_t1, ..., min_t100 represent min temperature from day1 to day100(`Date` day);
rf1, ..., rf100 represent rainfall from day1 to day100(`Date` day);
w1, ..., w100 represent wind from day1 to day100(`Date` day).

это новые имена столбцов (всего будет 400 новых столбцов).

Ответы [ 2 ]

0 голосов
/ 31 октября 2019

Я предполагаю, что столбец Дата в df1 имеет тип дата-время . Если нет, преобразуйте его.

Начните с таких подготовительных шагов:

  1. В df2 конвертируйте год / месяц / день столбцы индекс (из datetime тип):

    df2 = df2.set_index(pd.to_datetime(df2.year * 10000 + df2.month * 100
        + df2.day, format='%Y%m%d')).drop(columns=['year', 'month', 'day'])
    
  2. Установите количество дней, для которыхдобавьте столбцы:

    nDays = 3
    

    Для демонстрации я установил значение 3 , но вы можете изменить его на 100 или любое другое значение по вашему желанию.

  3. Определить имена столбцов для новых столбцов (первые import itertools ):

    cols = [ x + str(y) for x, y in itertools.product(
        ['max_t', 'min_t', 'rf', 'w'], range(1, nDays + 1)) ]
    
  4. Определить функцию для создания дополнительных столбцов,для текущей строки:

    def fn(row):
        d1 = row.Date
        d2 = d1 + pd.Timedelta(nDays - 1, 'D')
        return pd.Series(df2.loc[d1:d2].values.reshape((1, -1),
            order='F').squeeze(), index=cols)
    

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

df1 = df1.join(df1.apply(fn, axis=1))

Довольно краткое и в значительной степени решение pandasonic .

Для демонстрации работы этого решения я изменил yнаши данные немного:

df1:

   x0     x1    x2    x3       Date
0  40  31.05  25.5  25.5 2013-01-03
1  35  35.75  36.5  36.5 2013-01-07

df2 (начальное содержание):

   year  month  day  maxtemp  mintemp  rainfall  wind
0  2013      1    1     26.2     20.2         0  32.4
1  2013      1    2     22.9     20.3         0  10.0
2  2013      1    3     24.8     18.4         1  28.8
3  2013      1    4     26.6     18.3         2  33.5
4  2013      1    5     28.3     20.9         3  33.4
5  2013      1    6     28.0     21.6         4  32.8
6  2013      1    7     27.5     21.4         5  26.8
7  2013      1    8     42.3     20.9         6  25.5
8  2013      1    9     25.0     21.1         7  20.9
9  2013      1   10     25.4     20.2         8  14.0

df2 (после преобразования):

            maxtemp  mintemp  rainfall  wind
2013-01-01     26.2     20.2         0  32.4
2013-01-02     22.9     20.3         0  10.0
2013-01-03     24.8     18.4         1  28.8
2013-01-04     26.6     18.3         2  33.5
2013-01-05     28.3     20.9         3  33.4
2013-01-06     28.0     21.6         4  32.8
2013-01-07     27.5     21.4         5  26.8
2013-01-08     42.3     20.9         6  25.5
2013-01-09     25.0     21.1         7  20.9
2013-01-10     25.4     20.2         8  14.0

После добавления новых столбцов df1 содержит:

   x0     x1    x2    x3       Date  max_t1  max_t2  max_t3  min_t1  min_t2  \
0  40  31.05  25.5  25.5 2013-01-03    24.8    26.6    28.3    18.4    18.3   
1  35  35.75  36.5  36.5 2013-01-07    27.5    42.3    25.0    21.4    20.9   

   min_t3  rf1  rf2  rf3    w1    w2    w3  
0    20.9  1.0  2.0  3.0  28.8  33.5  33.4  
1    21.1  5.0  6.0  7.0  26.8  25.5  20.9  

Изменить после "100 дней до"comment

Если добавленные строки следует брать за 100 дней до текущей даты, измените способ установки обеих" дат границы "в функции fn . Что-то вроде:

def fn(row):
    d1 = row.Date - pd.Timedelta(nDays, 'D')
    d2 = row.Date - pd.Timedelta(1, 'D')
    return pd.Series(df2.loc[d1:d2].values.reshape((1, -1), order='F')
        .squeeze(), index=cols)

Как избежать увеличения количества строк

Если ваш df2 содержит несколько строк для некоторых дат, тогдаобъединение df1 с df2 приводит к увеличению числа выходных строк.

Если df2 имеет для некоторой даты, например, 3 строки, то для одна строка из df1 с этой датой результат будет содержать всего 3 строки (с одинаковой датой).

Чтобы избежать этого, вы должны "подавить" эти повторения.

Изначально я думал о df2 = df2.drop_duplicates (...) , но вы писали, что одна строка может содержать один набор значений, другие - другие наборы, поэтому мы не можемпроизвольно оставить одну строку и удалить другую (с той же даты).

Одним из возможных решений этой проблемы является то, что после создания «индекса даты» необходимо:

  • группа df2 по индексу (каждая группа будет содержать все строки на определенную дату),
  • compute означает каждого столбца (в нем отсутствуют возможные NaN значения),
  • сохраните результат обратно в df2 .

Код для этого:

df2 = df2.groupby(level=0).mean()

Тогда вы можете присоединиться (как описано выше), и количество выходных строк не должно увеличиваться.

0 голосов
/ 30 октября 2019

Я предлагаю сначала создать 400 новых столбцов в df2, а затем с помощью pandas.DataFrame.merge объединить его, сделав df1

, разбив две задачи:

ПРОБЛЕМА 1 : Рассчитать агрегированные значения за последние x дней

Ответили здесь

Применимо к вашей ситуации:

In[1]: df2 = pd.DataFrame({"year": [2013, 2013, 2013, 2013, 2013],
                           "month": [1, 1, 1, 1, 1],
                           "day": [1, 2, 3, 4, 5],
                           "mintemp": [26.2, 22.9, 24.8, 11.2, 10],
                           "maxtemp": [28.2, 23.9, 25.8, 22.1, 12]})
       # Create date column (type datetime64[ns])
       df2["date"] = pd.to_datetime((df2[["year", "month", "day"]]))
       # Add the 400 columns needed (I am only adding 2 as an example)
       # If you change 2 to 100 you will get your 100
       colnumber = 2
       # Maxtemp
       for i in range(1, colnumber + 1):
           col_name = "max_t" + str(i)
           df2[col_name] = df2.set_index("date").rolling(i).max()["maxtemp"].values
       # Mintemp
       for i in range(1, colnumber + 1):
           col_name = "min_t" + str(i)
           df2[col_name] = df2.set_index("date").rolling(i).min()["mintemp"].values
       # TODO: Add rainfall and wind

In[2]:df2
Out[2]: 
   year  month  day  mintemp  maxtemp       date  max_t1  max_t2  min_t1  min_t2
0  2013  1      1    26.2     28.2    2013-01-01  28.2   NaN      26.2   NaN    
1  2013  1      2    22.9     23.9    2013-01-02  23.9    28.2    22.9    22.9  
2  2013  1      3    24.8     25.8    2013-01-03  25.8    25.8    24.8    22.9  
3  2013  1      4    11.2     22.1    2013-01-04  22.1    25.8    11.2    11.2  
4  2013  1      5    10.0     12.0    2013-01-05  12.0    22.1    10.0    10.0  

ПРОБЛЕМА 2 : объединить два кадра данных по горизонтали, используя столбец даты в качестве общего ключа

Сначала вам нужно будет преобразовать столбцы в дату-время (аналогичные ответы здесь ), а затемобъединить DF с помощью общего ключа.

In[3]:df1 = pd.DataFrame({"x0": [40, 35, 33, 38],
                          "x1": [31.05, 35.75, 22, 28],
                          "x1000": [33, 29, 20, 18],
                          "Date": ["2013-1-1", "2013-1-2", "2013-1-3", "2013-1-4"]})
    # Creating common key with type datetime64[ns]
    df1["date"] = pd.to_datetime(df1["Date"])

Out[3]:
   x0     x1  x1000      Date       date
0  40  31.05  33     2013-1-1 2013-01-01
1  35  35.75  29     2013-1-2 2013-01-02
2  33  22.00  20     2013-1-3 2013-01-03
3  38  28.00  18     2013-1-4 2013-01-04

In[4]: # Merging
       df1.merge(df2, how="left", left_on=["date"], right_on=["date"])

Out[4]:
   x0     x1  x1000      Date       date  year  month  day  mintemp  maxtemp  max_t1  max_t2  min_t1  min_t2
0  40  31.05  33     2013-1-1 2013-01-01  2013  1      1    26.2     28.2     28.2   NaN      26.2   NaN    
1  35  35.75  29     2013-1-2 2013-01-02  2013  1      2    22.9     23.9     23.9    28.2    22.9    22.9  
2  33  22.00  20     2013-1-3 2013-01-03  2013  1      3    24.8     25.8     25.8    25.8    24.8    22.9  
3  38  28.00  18     2013-1-4 2013-01-04  2013  1      4    11.2     22.1     22.1    25.8    11.2    11.2 

РЕДАКТИРОВАТЬ: Добавлен вывод

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...