0

I have the following data frame looking as below:

print(df_example.to_dict())
{
    "slot_id": {
        0: 1,
        1: 2,
        2: 3,
        3: 4,
        4: 5
    },
    "class": {
        0: "A",
        1: "B",
        2: "C",
        3: "D",
        4: "E"
    },
    "day": {
        0: "Monday",
        1: "Tuesday",
        2: "Wednesday",
        3: "Thursday",
        4: "Saturday"
    },
    "base_date": {
        0: Timestamp("2019-01-21 00: 00: 00"),
        1: Timestamp("2019-01-22 00: 00: 00"),
        2: Timestamp("2019-01-23 00: 00: 00"),
        3: Timestamp("2019-01-24 00: 00: 00"),
        4: Timestamp("2019-01-26 00: 00: 00")
    },
    "next_date": {
        0: nan,
        1: nan,
        2: nan,
        3: nan,
        4: nan
    },
    "base_date_weekday": {
        0: 0,
        1: 1,
        2: 2,
        3: 3,
        4: 5
    }
}

df_example.head

For the column next_date, I would like to find the next date that is the day of the week in column day (Monday, Tuesday, etc.) from today's date using the lambda function below [found here]:

df_example['base_date'] = pd.to_datetime(df_example['base_date'].astype(str), format='%d%m%Y')
df_example['base_date_weekday'] = df_example['base_date'].dt.dayofweek
# Lambda function to find the next date that corresponds to a particular day of the week
onDay = lambda date, day: date + datetime.timedelta(days=(day-date.weekday()+7)%7)

The lambda function works with a simple integer.

df_example['next_date'] = onDay(date=datetime.date.today(), day=2)

But how could I pass the column day to the day parameter of the lambda so it does the calculation row by row? None of the following works:

df_example['next_date'] = onDay(date=datetime.date.today(), day=df_example['base_date_weekday'])
df_example['next_date'] = onDay(date=datetime.date.today(), day='base_date_weekday')

I have tried to use a function and df.apply without success either.

def next_weekday(weekday):
    todaydate = datetime.date.today()
    days_ahead = weekday - todaydate.weekday()
    if days_ahead <= 0: # Target day already happened this week
        days_ahead += 7
    return todaydate + datetime.timedelta(days_ahead)

df_example.apply(lambda base_date_weekday: next_weekday(base_date_weekday),axis=1)

Any idea how I could do this simple task?

user3507584
  • 3,246
  • 5
  • 42
  • 66
  • 1
    That function is written to expect a single value, not a pandas series whatever. – juanpa.arrivillaga Jan 28 '19 at 22:51
  • @juanpa.arrivillaga Thanks! May I ask why we cannot pass the variable, is it a characteristic of lambda functions? What is the solution, a `for loop`? Is there anything more "elegant" in Python like a `sapply` functional in R? – user3507584 Jan 28 '19 at 22:57
  • No, there is nothing special about a `lambda` function in that regard. You can use `.apply` if you want for pandas data-frames, although, that is usually the last resort, and it's not really more elegant than a for-loop (it essentially is a for-loop under the hood). And again, you can pass variables to that function just fine, but that function isn't written to accept the data-type you are trying to pass it. – juanpa.arrivillaga Jan 28 '19 at 22:58
  • 1
    As an aside, you shouldn't be using a `lambda` expression that you are just going to end up assigning to a variable. The *entire purpose* of lambda functions is that they are anonymous, that is their *only* useful feature. If you are going to assign the results of a lambda, just use a full function definition (this is actually explicitly in the PEP8 official python style guide) – juanpa.arrivillaga Jan 28 '19 at 23:01
  • @juanpa.arrivillaga I have tried defining a function and applying it by row but it doesn't work either :-( – user3507584 Jan 28 '19 at 23:39

1 Answers1

0

I managed to get the next weekday from today by means of defining a function and passing it in a for loop (!). I'm sure there are far more pythonic ways to do this, which I would really appreciate to see.

def next_weekday(weekday):
    todaydate = datetime.date.today()
    days_ahead = weekday - todaydate.weekday()
    if days_ahead <= 0: # Target day already happened this week
        days_ahead += 7
    return todaydate + datetime.timedelta(days_ahead)

for i in range(df_example.shape[0]):
    df_example.loc[i,'next_date'] = next_weekday(weekday=int(df_example.loc[i,'base_date_weekday']))
    print(df_example)
user3507584
  • 3,246
  • 5
  • 42
  • 66