Найти абсолютную разницу между 2 столбцами с датами разных форматов в виде количества дней - PullRequest
0 голосов
/ 30 мая 2019

Мне нужно найти абсолютную разницу в днях между двумя столбцами, у которых есть даты в python. Это довольно легко в Excel, но я хочу в Python.

У меня есть файл xlsx, который я прочитал в фрейм данных Python (используя pd.read_excel) с примером чтения данных, как показано ниже: Столбцы содержат информацию о дате в текстовом формате ddmmyyyy / dmmyyyy.

A B
1102012
26071993 27122007
28062010 3122015
16012010 21022016
02082015 14092010

Теперь мне нужно создать новый столбец C, в котором будет содержаться абсолютное число разниц в днях между A и B. A может быть меньше или больше B.
Если B пусто, то следует учитывать текущую дату для расчета дней. Но у A не будет пустых значений / NULL.

Таким образом, на выходе будет разница количества дней:

C
2432
5267
1984
2227
1783

Подход, которым я следовал, был:

  1. Преобразование A и B в 8 цифр, поскольку у нас есть только 7 цифр в некоторых значениях A и B - используя df['A'].apply(lambda x: '{0:0>8}'.format(x))
  2. Конвертировать A в поле даты и времени, используя pd.to_datetime
  3. Создайте еще один временный столбец, скажем, CC, скопировав значения B и все значения даты, отличные от NULL (то есть заменяя NULL / пусто на текущую дату)
  4. Затем найдите абсолютную разницу между A и CC (количество дней)

Я застрял на третьем шаге и не могу продолжить. Есть ли более простой способ сделать это?

Ответы [ 2 ]

3 голосов
/ 30 мая 2019

Первые варианты - хорошая идея.Избегает путаницы в отношении того, какой день или месяц.

# Recreate dataframe
df = pd.DataFrame([["1102012", pd.np.NaN],["26071993","27122007"],
                   ["28062010","3122015"],["16012010","21022016"],
                   ["02082015","14092010"]], columns=["A","B"]) 
print(df)
>>>
          A         B
0   1102012       NaN
1  26071993  27122007
2  28062010   3122015
3  16012010  21022016
4  02082015  14092010

print(df.dtypes)
>>>
A    object
B    object
dtype: object

Таким образом, фрейм данных, с которым мы работаем, находится выше.Все типы данных object (строка).Было бы хорошо, если бы вы могли подтвердить этот шаг, поскольку все остальное происходит отсюда.

# convert some datetimes
# Assumption is that column A is not sparse - there are no NaNs
# Column B can be NaN so make it today if so
m = df["B"].isnull()
df.loc[m, "B"] = pd.datetime.now().strftime("%d%m%Y") 
print(df)
>>>
          A         B
0   1102012  03062019
1  26071993  27122007
2  28062010   3122015
3  16012010  21022016
4  02082015  14092010

# now we zero pad some numbers
df['A'] = df['A'].apply(lambda x: '{0:0>8}'.format(x))
df['B'] = df['B'].apply(lambda x: '{0:0>8}'.format(x))
print(df)
>>>
          A         B
0  01102012  03062019
1  26071993  27122007
2  28062010  03122015
3  16012010  21022016
4  02082015  14092010

Затем используйте to_datetime:

df["A"] = pd.to_datetime(df["A"], format="%d%m%Y")
df["B"] = pd.to_datetime(df["B"], format="%d%m%Y")
print(df)
>>>
           A          B
0 2012-10-01 2019-06-03
1 1993-07-26 2007-12-27
2 2010-06-28 2015-12-03
3 2010-01-16 2016-02-21
4 2015-08-02 2010-09-14

print(df.dtypes)
>>>
A    datetime64[ns]
B    datetime64[ns]
dtype: object

Затем diff

df["Diff"] = (df["A"] - df["B"]).abs()
print(df)
>>>
           A          B      Diff
0 2012-10-01 2019-06-03 2436 days
1 1993-07-26 2007-12-27 5267 days
2 2010-06-28 2015-12-03 1984 days
3 2010-01-16 2016-02-21 2227 days
4 2015-08-02 2010-09-14 1783 days

# or
df["Diff"] = (df["A"] - df["B"]).abs().dt.days
print(df)
>>>
           A          B  Diff
0 2012-10-01 2019-06-03  2436
1 1993-07-26 2007-12-27  5267
2 2010-06-28 2015-12-03  1984
3 2010-01-16 2016-02-21  2227
4 2015-08-02 2010-09-14  1783
1 голос
/ 30 мая 2019

Редактировать : объяснить при ошибке

Как вы сказали, ошибка в комментарии. Это означает, что ваш столбец A не dtype object. Это либо int32, либо int64. Выполните эту команду для подтверждения ( Я изменил столбец данных примера A dtype, чтобы продемонстрировать ошибку ):

df.dtypes

Out[2866]:
A     int32
B    object
dtype: object

Перед использованием str.zfill вам необходимо изменить df на object следующим образом:

df = df.astype(str)

Out[2870]:
A    object
B    object
dtype: object

После преобразования dtype в object все будет работать.


zfill(8) для дополнения 0 до строк и преобразования их в datetime, используя pd.to_datetime с coerce и filna на NaT с сегодняшней датой. Затем выполните вычитание A и B, сделайте abs и получите days из timedelta

Примечание : добавление предварительной обработки для преобразования df dtype в object с использованием astype(str)

df = df.astype(str) 
df1 = df.apply(lambda x: pd.to_datetime(x.str.zfill(8), format='%d%m%Y', errors='coerce')).fillna(pd.datetime.today().date())
df1.A.sub(df1.B).abs().dt.days

Out[2599]:
0    2432
1    5267
2    1984
3    2227
4    1783
dtype: int64
...