我有一个这样的数据集:

df0 = (pd.DataFrame({'year_minor_renovation': ['2023', '2025', np.nan, '2026'],
               'year_intermediate_renovation': [np.nan, '2025', '2027', '2030'],
               'year_major_renovation': ['2030', np.nan, np.nan, np.nan],
               'costs_minor_renovation': [1000, 3000, np.nan, 2000],
               'costs_intermediate_renovation': [np.nan, 5000, 5000, 10000],
               'costs_major_renovation': [75000, np.nan, np.nan, np.nan]}))
year_minor_renovation year_intermediate_renovation year_major_renovation costs_minor_renovation costs_intermediate_renovation costs_major_renovation
0 2023 NaN 2030 1000.0 NaN 75000.0
1 2025 2025 NaN 3000.0 5000.0 NaN
2 NaN 2027 NaN NaN 5000.0 NaN
3 2026 2030 NaN 2000.0 10000.0 NaN

每一条线代表一座要翻新的建筑.可以将其视为具有相同索引的两个串联子集:

  • 2023年至2030年期间需要对特定建筑进行一次或多次翻新时,左半部分为df.iloc[:, :3](索引)
  • 右半部分是对应的成本

我想要的是

一些建筑在不同的年份需要不同的翻新类型(例如:df.iloc[[1]]).

我需要收集新的柱子,每年一根,与每座建筑的成本无关,无论翻修的类型是什么.

(pd.DataFrame({'2023': [1000, np.nan, np.nan, np.nan],
              '2024': [np.nan, np.nan, np.nan, np.nan],
              '2025': [np.nan, 8000, np.nan, np.nan],
              '2026': [np.nan, np.nan, np.nan, 2000],
              '2027': [np.nan, np.nan, 5000, np.nan],
              '2028': [np.nan, np.nan, np.nan, np.nan],
              '2029': [np.nan, np.nan, np.nan, np.nan],
              '2030': [75000, np.nan, 5000, 10000]}))
2023 2024 2025 2026 2027 2028 2029 2030
0 1000.0 NaN NaN NaN NaN NaN NaN 75000.0
1 NaN NaN 8000.0 NaN NaN NaN NaN NaN
2 NaN NaN NaN NaN 5000.0 NaN NaN 5000.0
3 NaN NaN NaN 2000.0 NaN NaN NaN 10000.0

我所try 的

我试图编写一个GROUPBY函数来创建这些新列,但即使结果提供了一些我稍后需要的数据,对于我当时想要的东西来说,这也是一种过度的合成:

def costs_per_year(df):
    dfs = []
    for i in ['year_minor_renovation',
              'year_intermediate_renovation',
              'year_major_renovation']:
        j =  'costs' + str(i[4:])
        df_ = (df.groupby(i)
               .agg({j : 'sum' })
               .reset_index()
               .rename({i:'year'}, axis =1)
              )
        dfs.append(df_)
        
        # merge the dataframes 
        merged_df = dfs[0]
    for df_ in dfs[1:]:
        merged_df = merged_df.merge(df_, on='year', how='outer')
    
    merged_df = (merged_df
                 .set_index('year')
                 .transpose()
                 .reset_index()
                )
   
    return merged_df
year index 2023 2025 2026 2027 2030
0 costs_minor_renovation 1000.0 3000.0 2000.0 NaN NaN
1 costs_intermediate_renovation NaN 5000.0 NaN 5000.0 10000.0
2 costs_major_renovation NaN NaN NaN NaN 750000.0

推荐答案

您可以使用pd.wide_to_long:

out = (pd.wide_to_long(df0.reset_index(), stubnames=['year', 'costs'], i='index', j='var', sep='_', suffix='.*')
         .dropna().astype({'year': int})
         .pivot_table(index='index', columns='year', values='costs', aggfunc='sum')
         .rename_axis(index=None, columns=None))

out = out.reindex(columns=range(out.columns.min(), out.columns.max()+1))

输出:

>>> out
     2023  2024    2025    2026    2027  2028  2029     2030
0  1000.0   NaN     NaN     NaN     NaN   NaN   NaN  75000.0
1     NaN   NaN  8000.0     NaN     NaN   NaN   NaN      NaN
2     NaN   NaN     NaN     NaN  5000.0   NaN   NaN      NaN
3     NaN   NaN     NaN  2000.0     NaN   NaN   NaN  10000.0

一步一步更好地理解转型:

# Step 1: flatten your dataframe
>>> out =  out = pd.wide_to_long(df0.reset_index(), stubnames=['year', 'costs'], i='index', j='var', sep='_', suffix='.*')
                               year    costs
index var                                   
0     minor_renovation         2023   1000.0
1     minor_renovation         2025   3000.0
2     minor_renovation          NaN      NaN
3     minor_renovation         2026   2000.0
0     intermediate_renovation   NaN      NaN
1     intermediate_renovation  2025   5000.0
2     intermediate_renovation  2027   5000.0
3     intermediate_renovation  2030  10000.0
0     major_renovation         2030  75000.0
1     major_renovation          NaN      NaN
2     major_renovation          NaN      NaN
3     major_renovation          NaN      NaN

# Step 2: cast year to int
>>> out = out.dropna().astype({'year': int})
                               year    costs
index var                                   
0     minor_renovation         2023   1000.0
1     minor_renovation         2025   3000.0
3     minor_renovation         2026   2000.0
1     intermediate_renovation  2025   5000.0
2     intermediate_renovation  2027   5000.0
3     intermediate_renovation  2030  10000.0
0     major_renovation         2030  75000.0

# Step 3: reshape your dataframe
>>> out = out.pivot_table(index='index', columns='year', values='costs', aggfunc='sum')
year     2023    2025    2026    2027     2030
index                                         
0      1000.0     NaN     NaN     NaN  75000.0
1         NaN  8000.0     NaN     NaN      NaN
2         NaN     NaN     NaN  5000.0      NaN
3         NaN     NaN  2000.0     NaN  10000.0

# Step 4: rename axis
>>> out = out.rename_axis(index=None, columns=None)
     2023    2025    2026    2027     2030
0  1000.0     NaN     NaN     NaN  75000.0
1     NaN  8000.0     NaN     NaN      NaN
2     NaN     NaN     NaN  5000.0      NaN
3     NaN     NaN  2000.0     NaN  10000.0

# Step 5: add missing columns
>>> out = out.reindex(columns=range(out.columns.min(), out.columns.max()+1))
     2023  2024    2025    2026    2027  2028  2029     2030
0  1000.0   NaN     NaN     NaN     NaN   NaN   NaN  75000.0
1     NaN   NaN  8000.0     NaN     NaN   NaN   NaN      NaN
2     NaN   NaN     NaN     NaN  5000.0   NaN   NaN      NaN
3     NaN   NaN     NaN  2000.0     NaN   NaN   NaN  10000.0

Python相关问答推荐

无法使用equals_html从网址获取全文

当密钥是复合且唯一时,Pandas合并抱怨标签不唯一

如何使用Jinja语法在HTML中重定向期间传递变量?

连接两个具有不同标题的收件箱

切片包括面具的第一个实例在内的眼镜的最佳方法是什么?

Julia CSV for Python中的等效性Pandas index_col参数

如果条件不满足,我如何获得掩码的第一个索引并获得None?

使用NeuralProphet绘制置信区间时出错

在Python中,从给定范围内的数组中提取索引组列表的更有效方法

如何在Python中获取`Genericums`超级类型?

如何使用SentenceTransformers创建矢量嵌入?

如何在PySide/Qt QColumbnView中删除列

如何在Python中使用Iscolc迭代器实现观察者模式?

为罕见情况下的回退None值键入

Pandas:计数器的滚动和,复位

在pandas中,如何在由两列加上一个值列组成的枢轴期间或之后可靠地设置多级列的索引顺序,

PYTHON中的selenium不会打开 chromium URL

在Pandas 中以十六进制显示/打印列?

如何在Python中实现高效地支持字典和堆操作的缓存?

我可以同时更改多个图像吗?