如何解决 ValueError:无法从重复轴重新索引

时间:2021-07-28 08:08:07

标签: python pandas dataframe numpy date

输入

<头>
客户 名字 姓氏 开始日期 结束日期 金额 发票日期
XXX 约翰 肯尼迪 15-01-2021 28-02-2021 137,586.00 20-04-2021
YYYY 彼得 保罗 7-02-2021 31-03-2021 38,750.00 20-04-2021
ZZZ 迈克尔 K 10-03-2021 29-04-2021 137,586.00 30-04-2021

代码

df = pd.read_excel ('file.xlsx',parse_dates=['Start Date','End Date'] )
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')

df['r'] = df.apply(lambda x: pd.date_range(x['Start Date'],x['End Date']), axis=1)
df = df.explode('r')
print(df)

months = df['r'].dt.month

starts, ends = months.ne(months.groupby(level=0).shift(1)), months.ne(months.groupby(level=0).shift(-1))


df2 = pd.DataFrame({'First Name': df['First name'],
           'Start Date': df.loc[starts, 'r'].dt.strftime('%Y-%m-%d'),
                   'End Date': df.loc[ends, 'r'].dt.strftime('%Y-%m-%d'),
                   'Date Diff': df.loc[ends, 'r'].dt.strftime('%d').astype(int)-df.loc[starts, 'r'].dt.strftime('%d').astype(int)+1})

df = df.loc[~df.index.duplicated(), :]

df2 = pd.merge(df, df2, left_index=True, right_index=True)

df2['Amount'] = df['Amount'].mul(df2['Date_Diff'])
print(df['Amount'])
print (df)

df.to_excel('report.xlsx', index=True)

错误 ValueError:无法从重复轴重新索引

预期输出

enter image description here

如何解决这个问题?

1 个答案:

答案 0 :(得分:1)

首先在输入的 Excel 文件中进行一些更正,即更改名字 名字 - 使用大写“N”,就像在其他列中一样。

然后,要读取您的 Excel 文件,只需运行:

df = pd.read_excel('Input.xlsx', parse_dates=['Start Date', 'End Date',
   'Invoice Date'], dayfirst=True)

无需调用 to_datetime

还要注意,由于 Invoice Date 也包含日期,我将此列添加到 parse_dates 列表。

然后定义两个函数:

  1. 获取当前行每月数据的函数:

    def getMonthData(grp, amnt, dayNo):
        return pd.Series([grp.min(), grp.max(), amnt * grp.size / dayNo],
            index=['Start Date', 'End Date', 'Amount'])
    

    它将输入的日期系列(单月)转换为“新”内容 输出行(开始/结束日期和总金额的适当份额,为 本月入账)。

    它将在以下函数中调用。

  2. “爆炸”当前行的函数:

    def rowExpl(row):
        ind = pd.date_range(row['Start Date'], row['End Date']).to_series()
        rv = ind.groupby(pd.Grouper(freq='M')).apply(getMonthData,
            amnt=row.Amount, dayNo=ind.size).unstack().reset_index(drop=True)
        rv.insert(0, 'Client', row.Client)
        rv.insert(1, 'First Name', row['First Name'])
        rv.insert(2, 'Last Name', row['Last Name'])
        return rv.assign(**{'Invoice Date': row['Invoice Date']})
    

最后一步是得到结果。将 rowExpl 应用于每一行并连接 将部分结果转化为单个输出 DataFrame:

result = pd.concat(df.apply(rowExpl, axis=1).values, ignore_index=True)

对于您的数据样本,结果是:

  Client First Name Last Name Start Date   End Date   Amount Invoice Date
0    XXX       John   Kennedy 2021-01-15 2021-01-31  51976.9   2021-04-20
1    XXX       John   Kennedy 2021-02-01 2021-02-28  85609.1   2021-04-20
2    YYY      Peter      Paul 2021-02-07 2021-02-28  16084.9   2021-04-20
3    YYY      Peter      Paul 2021-03-01 2021-03-31  22665.1   2021-04-20
4    ZZZ    Michael         K 2021-03-10 2021-03-31  59350.8   2021-04-30
5    ZZZ    Michael         K 2021-04-01 2021-04-29  78235.2   2021-04-30

不要因为 Amount 列的精度似乎太低而感到不满。 这只是 Jupyter Notebook 显示 DataFrame 的方式。

当您运行 result.iloc[0, 5] 时,您将获得:

51976.933333333334

完全,实际上保持精确。

相关问题