Как объединить дату в Pandas с поддержкой нескольких форматов данных? - PullRequest
3 голосов
/ 07 октября 2019

Я пишу библиотеку процедур Pandas, которая должна иметь возможность обрабатывать даты во фреймах данных, которые потенциально могут быть разных типов. В частности, я получаю различные комбинации типов datetime.date и pandas._libs.tslib.Timestamp совсем немного. Сообщается (и подтверждено моими испытаниями), что это связано с кадрами, для которых был установлен многоиндексный набор, а затем сброшен. (См. Мой предыдущий вопрос Что меняет тип даты в этом коде панд? , который решает проблему изменения типа при переходе назад и вперед от мультииндекса.)

Воткороткий (но надуманный) пример:

import pandas as pd
df = pd.DataFrame(
   data={
      'date' : ['2019-01-01', '2019-01-02', '2019-01-03'], 
      'value' : [1, 2, 3], 
      'other' : [11, 12, 13]
   }
)

df.date = pd.to_datetime(df.date).dt.date

print df.head()
         date  other  value
0  2019-01-01     11      1
1  2019-01-02     12      2
2  2019-01-03     13      3

df_reindex = df.set_index(['date','other']).reset_index()
         date  other  value
0  2019-01-01     11      1
1  2019-01-02     12      2
2  2019-01-03     13      3

print pd.merge(df, df_reindex, on='date')
Empty DataFrame
Columns: [date, other_x, value_x, other_y, value_y]
Index: []

print pd.merge(df, df, on='date')
         date  other_x  value_x  other_y  value_y
0  2019-01-01       11        1       11        1
1  2019-01-02       12        2       12        2
2  2019-01-03       13        3       13        3

print pd.merge(df_reindex, df_reindex, on='date')
        date  other_x  value_x  other_y  value_y
0 2019-01-01       11        1       11        1
1 2019-01-02       12        2       12        2
2 2019-01-03       13        3       13        3

print type(df.date[0])
<type 'datetime.date'>

print type(df_reindex.date[0])
<class 'pandas._libs.tslib.Timestamp'>

Здесь и df, и df_reindex имеют по существу одинаковое содержимое данных, но из-за того, что тип был изменен внутри Панд в точке set_index, слияние между ними пустое, в то время как «самослияние» между любым из двух с самим собой дает ожидаемый (хотя, в данном случае надуманный, избыточный и тривиальный) результат.

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

Есть комментарий к моему другому вопросу об использовании даты и времени NumPy, но это кажется бесполезным, поскольку преобразование, очевидно, приводит к одному из двух проблемных типов данных, то естьбазовый класс Pandas:

df_numpy = df.copy()

df_numpy.date = df.date.apply(np.datetime64)

print type(df.date[0])
<type 'datetime.date'>

print type(df_numpy.date[0])
<class 'pandas._libs.tslib.Timestamp'>

(Не говоря уже о том, что я работаю в рамках существующего фреймворка, поэтому на данном этапе может быть невозможно заставить все кадры иметь типы NumPy вместо типов Pandas.)

Что мне нужно сделать, так это уметь объединять таблицы внутри кода библиотеки, независимо от того, были ли они так манипулированы вызывающей стороной вне моего контроля. Кадры данных, которые я получаю в качестве входных данных, не могут быть изменены. Я мог бы скопировать их и реализовать прямое преобразование копий (как здесь панды объединяются при выпуске столбца даты ), но рамки иногда бывают большими, и я не хочу копировать их, если нет другого выбора.

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

1 Ответ

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

Есть ли способ заставить объединение распознать их как эквивалентные?

Нет, не с текущим кодом панд :

    # datetimelikes must match exactly
    elif is_datetimelike(lk) and not is_datetimelike(rk):
        raise ValueError(msg)
    elif not is_datetimelike(lk) and is_datetimelike(rk):
        raise ValueError(msg)
    elif is_datetime64tz_dtype(lk) and not is_datetime64tz_dtype(rk):
        raise ValueError(msg)
    elif not is_datetime64tz_dtype(lk) and is_datetime64tz_dtype(rk):
        raise ValueError(msg)

Если нет, то существует ли наилучший выбор формата даты, которыйизбегает проблемы конверсии, выставленной здесь?

Из вашего вопроса я понимаю, что кадры данных и их типы данных находятся вне вашего контроля и их нельзя изменить, поэтому этот вопрос ни к чему нас не приведет.


Вам понадобится условное соединение, как в SQL. Существует старая открытая проблема для этой функции без активности с 2014 года. (PR приглашаются ...)


Возможный обходной путь будет выглядеть примерно такчто:
def merge_on_date(left, right, on):
    from pandas.core.dtypes.common import is_datetimelike
    try:
        return pd.merge(left, right, on=on)
    except:
        if is_datetimelike(right[on]):
            return pd.merge(left, right.assign(**{on: eval('right[on].dt.date')}), on=on)
        else:
            return pd.merge(left.assign(**{on: eval('left[on].dt.date')}), right, on=on)

Результат:

>>> merge_on_date(df, df_reindex, 'date')
         date  value_x  other_x  other_y  value_y
0  2019-01-01        1       11       11        1
1  2019-01-02        2       12       12        2
2  2019-01-03        3       13       13        3
>>> merge_on_date(df_reindex, df, 'date')
         date  other_x  value_x  value_y  other_y
0  2019-01-01       11        1        1       11
1  2019-01-02       12        2        2       12
2  2019-01-03       13        3        3       13

Однако этот большой недостаток заключается в том, что assign делает копию под капотом.

PS: я только что увидел, что pd.merge(df, df_reindex, on='date') приводит к пустому кадру данных в вашем примере. Начиная с версии 0.22.0 это должно повысить ValueError. Какую версию вы используете?

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