преобразование набора данных с помощью условий

#python #pandas

#python #pandas

Вопрос:

Значения соответствуют типу плана, который есть у клиента:

df (только строка)

 Customer|mar_x|abr|may|jun|jul|aug |sep|oct|nov|dez|jan|feb|mar_y                 
x        |NaN  |NaN|NaN|NaN|7.5|30.0|7.5|7.5|7.5|7.5|7.5|7.5|7.5
  

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

если не было значения, это будет «новым», если значение равно предыдущему, будет «существующим», если значение больше, чем раньше, «обновленным», если значение меньше, чем раньше, «пониженным»

Требуется вывод:

 Mar_x|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec|Jan|Feb|Mar_y
-    |-  |-  |-  | N | U | D | E |E  |  E|E  |E  |E
  

Комментарии:

1. Хранятся ли данные для клиента за предыдущий месяц в другой строке этого фрейма данных? Если да, можем ли мы предположить, что фрейм данных отсортирован по дате (и если нет, можете ли вы добавить дату к фрейму данных, чтобы можно было сортировать по дате)?

2. это не сохраняется. это был интервал от start_date до end_date, который я только что превратил в этот набор данных, разделенный месяцами, со значениями

3. Ах да. Я понимаю, к чему вы стремитесь. Минутку.

Ответ №1:

Это должно сделать то, что вы ищете:

 # read in your data
df = pd.DataFrame.from_records([
    [np.nan,7.5,30.0,np.nan,7.5,30.0,7.5,np.nan,np.nan,7.5,7.5,np.nan,np.nan]],
    columns=['Mar_x','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec','Jan','Feb','Mar_y'])

# function to return the new, upgrade, downgrade, etc
def value_comparison(diff):
    if diff==0:
        return 'E'
    elif diff > 0:
        return 'U'
    elif diff < 0:
        return 'D'
    else:
        return 'N'

# get the forward difference in time
df_diff = df.ffill(axis=1).diff(axis=1)
# apply the map to return your states
df_results = df_diff.apply(lambda row: row.apply(value_comparison), axis=1)
# correct for the NaN states where the forward difference was not defined
df_results[df.isna()]= np.nan
# correct for the case when the user cancels
mask = (df.isna() amp; ~df.shift(1, axis=1).isna())
df_results[mask] = 'C'
# correct for renew
mask = (~df.isna() amp; df.shift(1, axis=1).isna())
df_results[mask[mask == True].cumsum(axis=1) > 1] = 'Renew'
# result
print(df_results)
  

Результат:

   Mar_x Apr May Jun    Jul Aug Sep Oct  Nov    Dec Jan Feb Mar_y
0   NaN   N   U   C  Renew   U   D   C  NaN  Renew   E   C   NaN
  

Комментарии:

1. Я пытался применить аналогичный подход: состояние определения (строка): если (строка[-1]> строка[-2]) amp; (строка[-2] не равна None): возвращает ‘Обновленный’ elif (строка[-2] не равна None) amp; (строка[-1] не равна None): возвращает ‘Новый’ elif (строка[-1] не равна None) amp; (строка[-2] не равна None): возвращает ‘Сбитый’ elif (строка [-1] ==строка [-2]) amp; (строка[-1] равна not None): возвращает ‘Existing’ df_test = df4.apply(status, axis = 1) но это создало бы просто один столбец, поэтому мне пришлось бы перебирать другие столбцы и создавать новый DF на основе этого

2. Кроме того, используя ваш метод, мне пришлось сравнить значение с предыдущим столбцом. Вы знаете, как мы могли бы это сделать?

3. Не могли бы вы немного уточнить? Что вы имеете в виду, говоря «мне пришлось сравнить значение с предыдущим столбцом»? df.diff(axis=1) Метод, описанный выше, выполняет это сравнение.

4. для этого экземпляра он не получает новые значения i.imgur.com/cX0Jm2t.png

5. Ваше решение с использованием shift является хорошим. Должны быть способы изменить то, что вы хотите от маски: mask = (~df.isna() amp; df.shift(1, axis=1).isna()) # all items that have an item to the left being NaN и затем mask[mask == True].cumsum(axis=1)