Фреймы данных Python pandas - преобразование 2 столбцов с диапазонами дат - в ежемесячные столбцы для каждого месяца - PullRequest
0 голосов
/ 13 декабря 2018

Я новичок в Python, начинаю использовать Pandas для замены некоторых процессов, выполняемых в MS Excel.

Ниже приведено описание моей проблемы

Исходный кадр данных:

Contract Id, Start date, End date

 12378,   '01-01-2018', '15-05-2018'
 45679,   '10-03-2018', '31-07-2018'
 567982,  '01-01-2018', '31-12-2020'

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

Contract Id , Start date, End date, Jan-18,Feb-18,Mar-18,Apr-18,May-18...Dec-18
    12378, '01-01-2018', '15-05-2018', 1, 1, 1, 1, 1, 0, 0, 0, 0, .....,0
    45679, '10-03-2018', '31-07-2018', 0, 0, 1, 1, 1, 1, 1, 0, 0, 0....,0
    567982,'01-01-2018', '31-12-2020', 1, 1, 1, 1.........………..., 1, 1, 1

Я хотел бы создать набор новых столбцовс Идентификатором месяца в качестве заголовков столбцов и заполнить их флагом (1 или 0), если контракт активен в течение указанного месяца.

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

Ответы [ 3 ]

0 голосов
/ 13 декабря 2018

Этот подход использует очень богатую функциональность дат в пандах, в частности PeriodIndex

import pandas as pd
import numpy as np
from io import StringIO

# Sample data (simplified)
df1 = pd.read_csv(StringIO("""
'Contract Id','Start date','End date'
12378,'01-02-2018','15-03-2018'
45679,'10-03-2018','31-05-2018'
567982,'01-01-2018','30-06-2018'
"""), quotechar="'", dayfirst=True, parse_dates=[1,2])

# Establish the month dates as a pandas PeriodIndex, using month end 
dates = pd.period_range(df1['Start date'].min(), df1['End date'].max(), freq="M")

# create new dataframe with date matches with apply
# Match the start dates to the periods using the Period dates comparisons
# AND the result elementwise   using numpy logial _nd
data = df1.apply(lambda r: pd.Series(np.logical_and(r[1] <= dates, r[2] >= dates).astype(int)), axis=1)

# Data frame with named month columns
df2 = pd.DataFrame(data)
df2.columns = dates

# Cooncatenate 
result = pd.concat([df1, df2], axis=1)
result


#   Contract Id Start date   End date  2018-01  2018-02  2018-03  2018-04  2018-05  2018-06
#0        12378 2018-02-01 2018-03-15        0        1        1        0        0        0
#1        45679 2018-03-10 2018-05-31        0        0        1        1        1        0
#2       567982 2018-01-01 2018-06-30        1        1        1        1        1        1
0 голосов
/ 13 декабря 2018

Pandas поставляется с множеством встроенных методов обработки даты / времени, которые можно здесь использовать.

# SETUP
# -----
import pandas as pd

# Initialize input dataframe
data = [
    [12378, '01-01-2018', '15-05-2018'],
    [45679, '10-03-2018', '31-07-2018'],
    [567982, '01-01-2018', '31-12-2020'],
]
columns = ['Contract Id', 'Start date', 'End date']
df = pd.DataFrame(data, columns=columns)

# SOLUTION
# --------
# Convert strings to datetime objects
df['Start date'] = pd.to_datetime(df['Start date'], format='%d-%m-%Y')
df['End date'] = pd.to_datetime(df['End date'], format='%d-%m-%Y')

# For each month in year 2018 ...
for x in pd.date_range('2018-01', '2018-12', freq='MS'):
    # Create a column with contract-active flags
    df[x.strftime("%b-%y")] = (df['Start date'].dt.month <= x.month) & (x.month <= df['End date'].dt.month)

    # Optional: convert True/False values to 0/1 values
    df[x.strftime("%b-%y")] = df[x.strftime("%b-%y")].astype(int)

, что дает в результате:

In [1]: df
Out[1]:
   Contract Id Start date   End date  Jan-18  Feb-18  Mar-18  Apr-18  May-18  Jun-18  Jul-18  Aug-18  Sep-18  Oct-18  Nov-18  Dec-18
0        12378 2018-01-01 2018-05-15       1       1       1       1       1       0       0       0       0       0       0       0
1        45679 2018-03-10 2018-07-31       0       0       1       1       1       1       1       0       0       0       0       0
2       567982 2018-01-01 2020-12-31       1       1       1       1       1       1       1       1       1       1       1       1
0 голосов
/ 13 декабря 2018

Я также новичок в пандах.Может быть, есть лучший способ сделать это, но вот что у меня есть:

data['S_month'] = data['S'].apply(lambda x:int(x.split('-')[1]))
data['E_month'] = data['E'].apply(lambda x:int(x.split('-')[1]))
months = []
for s_e in data[['S_month','E_month']].values:
    month = np.zeros(12)
    month[s_e[0]-1:s_e[1]] = 1
    months.append(month)
months = pd.DataFrame(months,dtype=int,columns=np.arange(1,13))
data.join(months)

Или вы можете просто пропустить первые две строки и сделать это:

months = []
for s_e in data[['S','E']].values:
    month = np.zeros(12)
    month[int(s_e[0].split('-')[1])-1:int(s_e[1].split('-')[1])] = 1
    months.append(month)
months = pd.DataFrame(months,dtype=int,columns=np.arange(1,13))
data.join(months)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...