Как перебрать столбец в Pandas.DataFrame и добавить результат функции в ту же строку? - PullRequest
1 голос
/ 15 октября 2019

У меня есть Pandas.DataFrame, сгенерированный с помощью следующего CSV:

Category,Brand,Product Name,Price,Expiration Date, Package ID,Quantity
Cat1,Brand1,Product1,$1000,07/14/2020,XXXXXX,34

Я пытаюсь добавить столбец в CSV с целым числом в каждой строке, соответствующим тому, как скоро истекает срок действия (4 означает более 6 месяцев, 3 означает от 3 до 6 месяцев и т. Д.).

Моя проблема заключается в том, что при попытке преобразовать столбец Expiration Date в datetime (используя pandas.to_datetime(df['Expiration Date'])), а затемПримените мою функцию classify_expiration(), типы либо не совпадают с указанными в функции, либо пытаются применить функцию к index 0, что, как я считаю, является заголовком (и, следовательно, не соответствует формату %m/%d/%Y). Я попытался преобразовать столбец в дату и время внутри функции классификации, а также за ее пределами до вызова .apply(). Я также пытался использовать timedelta, чтобы сравнить даты истечения срока с текущей текущей датой, но он не работает с datetime.date.today().

Вот первый способ, которым я попробовал:

def classify_expiration(row):    
    one_week = timedelta(weeks=1, days=0, hours=0, minutes=0, seconds=0)

    if ((one_week * 0) <= (date.today() - row['Expiration Date']) <= (one_week * 4)):
        return 4

Этот способ дает мне ошибки, связанные с неправильными типами на index 0 или невозможностью применить функцию к серии.

Вот что я только что попробовал, что дает мне AssertionError:

def days_between(date1, date2):
    """Calculates the number of days between two dates

    Keyword arguments:
    date1 -- The first date in the subtraction.
    date2 -- The second date in the subtraction.
    """
    date1 = datetime.strptime(date1, '%m/%d/%Y')
    date2 = datetime.strptime(date2, '%m/%d/%Y')
    return abs((date2 - date1).days)


def classify_expiration(row):
    """Calculate days/weeks to expiration. Assign quartile based on value.

    Keyword arguments:
    row -- row in a `pandas.core.frame.DataFrame` object. e.g. `df['A']`
    """

    date_today = datetime.strptime(
        date.today().strftime('%m/%d/%Y'), '%m/%d/%Y')

    if (days_between(row, date_today) <= 30):
        return 4
    if (31 <= days_between(row, date_today) <= 90):
        return 3
    if (91 <= days_between(row, date_today) <= 120):
        return 2
    if (days_between(row, date_today) >= 121):
        return 1

Вот где я пытаюсь применить функцию:

# Convert column to `datetime` if its current type is str
pd.to_datetime(product_sales['Expiration Date'])

# Applying the `classify_expiration()` function
product_sales['Expiration Quartile'] = product_sales.apply(
    lambda row: classify_expiration(row), axis=1
)

Я ожидаю, что функция добавит новый столбец в DataFrame, который содержит сгенерированный квартиль для даты истечения срока в каждой строке. ,Я получу ошибки, которые варьируются от AssertionError, argument 1 must be str, not Series и других ошибок, связанных с index 0.

1 Ответ

1 голос
/ 15 октября 2019

Вам нужно удалить преобразование в datetime в функции days_between, если присвоить обратно product_sales['Expiration Date'] = pd.to_datetime(product_sales['Expiration Date']), а затем использовать product_sales['Expiration Date'].apply(classify_expiration) для цикла по скалярам:

def days_between(date1, date2):
    """Calculates the number of days between two dates

    Keyword arguments:
    date1 -- The first date in the subtraction.
    date2 -- The second date in the subtraction.
    """
    return abs((date2 - date1).days)


product_sales['Expiration Date'] = pd.to_datetime(product_sales['Expiration Date'])

product_sales['Expiration Quartile'] = (product_sales['Expiration Date']
                                               .apply(classify_expiration))
print (product_sales)
  Category   Brand Product Name  Price Expiration Date Package ID  Quantity  \
0     Cat1  Brand1     Product1  $1000      2020-07-14     XXXXXX        34   

   Expiration Quartile  
0                    1  

Панды имеют специальные функции для binnig, поэтому вместовозможна функция cut:

product_sales['Expiration Date'] = pd.to_datetime(product_sales['Expiration Date'])

product_sales['Expiration Quartile'] = (product_sales['Expiration Date']
                                             .apply(classify_expiration))

s = product_sales['Expiration Date'].sub(pd.to_datetime('today').floor('d')).dt.days

product_sales['Expiration Quartile1'] = pd.cut(s, 
                                               bins=[0, 30, 90,120, np.inf], 
                                               labels=[4,3,2,1])
print (product_sales)
  Category   Brand Product Name  Price Expiration Date Package ID  Quantity  \
0     Cat1  Brand1     Product1  $1000      2020-07-14     XXXXXX        34   
1     Cat1  Brand1     Product1  $1000      2020-01-13     XXXXXX        34   
2     Cat1  Brand1     Product1  $1000      2019-11-01     XXXXXX        34   
3     Cat1  Brand1     Product1  $1000      2020-01-15     XXXXXX        34   

   Expiration Quartile Expiration Quartile1  
0                    1                    1  
1                    3                    3  
2                    4                    4  
3                    2                    2  
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...