Я пытаюсь амортизировать стоимость проекта линейно по месяцам по всей длине проекта.

Для этого я перебираю фрейм данных проектов с определенной функцией, которая превратит каждую строку (или проект) в новый фрейм данных графиков затрат.

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

Вот моя определенная функция:

    def amortizeProject(name, start, end, cost):
      """ Create an amortized cost schedule by month for a given project where:
        name = project Name
        start = start date of project
        end = end date of project
        cost = total cost of project
      """
      # Create an index of the payment dates
      rng = pd.date_range(start, end, freq='MS')
      rng.name = "Cost_Date"

      # Build up the Amortization schedule as a DataFrame
      df = pd.DataFrame(index=rng,columns=['Name','Period_Cost'], dtype='float')

      # Add index by period
      df.reset_index(inplace=True)
      df.index += 1
      df.index.name = "Period"
      df["Name"] = name
      df["Period_Cost"] = np.pmt(0, rng.size, cost)

      # Return the new dataframe
      df = df.round(2)
      return df

Я пытаюсь перебрать мой initial_dataframe, т.е.

            Name       Start         End     Cost
    0  Project 1  2019-07-01  2020-07-01  1000000
    1  Project 2  2020-01-01  2021-03-31   350000

Используя функцию так:

    new_dataframe = initial_dataframe.apply(lambda x: amortizeProject(x['Name'], x['Start'], x['End'], x['Cost']), axis=1)

В идеале new_dataframe - это объединение всех полученных итераций, но я не уверен в правильном способе форматирования вывода функции .apply для этого. Я знаю, что функция дает ожидаемые результаты за одну итерацию.

Кроме того, я довольно новичок в Pandas, поэтому, если есть лучший / более оптимизированный способ сделать это, я хотел бы услышать это.

1
MBguitarburst 28 Июн 2019 в 19:58

3 ответа

Лучший ответ

Я закончил со следующим решением, которое работало для меня, используя глобальный фрейм данных:

globalDF = pd.DataFrame(columns=['Cost_Date','Name','Period_Cost'])

А затем во время итераций функции я использую функцию concat для построения глобального:

globalDF = pd.concat([globalDF,df])

Это очень похоже на метод добавления списка.

0
MBguitarburst 2 Июл 2019 в 14:39

Я думаю, что самый чистый вариант может быть комбинацией apply и stack .. поэтому используйте .apply вдоль строк, чтобы вернуть pd.Series (где индекс - это каждая дата в расписании и значения являются амортизированными значениями), а затем используйте .stack, чтобы свести значения в их законные места, например

def amortize(sers):
    values = #get the values
    dates = #get the dates
    return pd.Series(values, index=dates)

new_df = initial_dataframe.apply(amortize, axis=1).stack()
1
Ouyang Ze 29 Июн 2019 в 18:50

Вместо форматирования .apply(), я думаю, вы можете добиться этого с помощью этого:

Инициализируйте пустой список для хранения всех ваших df, df_list = []. Заполните его во время итерации внутри функции, df_list.append(df). После итерации объедините все df, хранящиеся в этом списке, с df df = pd.concat(df_list).

Поэтому код, который вы разместили, должен быть:

def amortizeProject(name, start, end, cost):
  """ Create an amortized cost schedule by month for a given project where:
    name = project Name
    start = start date of project
    end = end date of project
    cost = total cost of project
  """
  # Create an index of the payment dates
  rng = pd.date_range(start, end, freq='MS')
  rng.name = "Cost_Date"

  # Build up the Amortization schedule as a DataFrame
  df = pd.DataFrame(index=rng,columns=['Name','Period_Cost'], dtype='float')

  # Add index by period
  df.reset_index(inplace=True)
  df.index += 1
  df.index.name = "Period"
  df["Name"] = name
  df["Period_Cost"] = np.pmt(0, rng.size, cost)

  # Return the new dataframe
  df = df.round(2)
  df_list.append(df)
  return df_list


df_list = []
new_dataframe = initial_dataframe.apply(lambda x: amortizeProject(x['Name'], x['Start'], x['End'], x['Cost']), axis=1)
df = pd.concat(df_list)
print(df)

Результат должен выглядеть как этот

1
Joe 11 Сен 2019 в 15:18