【问题标题】:Merging two multiindex dataframes合并两个多索引数据框
【发布时间】:2021-09-21 10:14:27
【问题描述】:

我有 2 个数据框:

df1 = pd.DataFrame.from_dict({('category', ''): {0: 'A',
  1: 'B',
  2: 'C',
  3: 'D',
  4: 'E',
  5: 'F',
  6: 'G'},
 (pd.Timestamp('2021-06-28 00:00:00'),
  'metric_1'): {0: 4120.549999999999, 1: 11226.016666666665, 2: 25049.443333333333, 3: 18261.083333333332, 4: 2553.1208333333334, 5: 2843.01, 6: 73203.51333333334},
 (pd.Timestamp('2021-06-28 00:00:00'), 'metric_2'): {0: 9907.79,
  1: 7614.650000000001,
  2: 13775.259999999998,
  3: 13158.250000000004,
  4: 1457.85,
  5: 1089.5600000000002,
  6: 38864.9},
 (pd.Timestamp('2021-07-05 00:00:00'),
  'metric_1'): {0: 5817.319999999998, 1: 10799.45, 2: 23521.51, 3: 22062.350833333334, 4: 1249.5974999999999, 5: 3229.77, 6: 52796.06083333332},
 (pd.Timestamp('2021-07-05 00:00:00'), 'metric_2'): {0: 6321.21,
  1: 5606.01,
  2: 10239.689999999999,
  3: 17476.600000000002,
  4: 943.7199999999999,
  5: 1410.33,
  6: 29645.45}}).set_index('category')
df2 = pd.DataFrame.from_dict({'category': {0: 'A',
  1: 'B',
  2: 'C',
  3: 'D',
  4: 'E',
  5: 'F',
  6: 'G'},
 1: {0: 36234.035577957984,
  1: 69078.07089184562,
  2: 128879.5397517309,
  3: 178376.63536908248,
  4: 9293.956915067887,
  5: 8184.780211399392,
  6: 177480.74540313095},
 2: {0: 37887.581678419825,
  1: 72243.67956241772,
  2: 134803.02342121338,
  3: 186603.8963173654,
  4: 9716.385738295368,
  5: 8555.606693927,
  6: 185658.87577993725}}).set_index('category')

首先我将df2的列名更改为与df相同

date_mappings = {
1 : '2021-06-28',
2 : '2021-07-05'}

df2 = df2.rename(columns=date_mappings)

然后我尝试合并它

f = lambda x: pd.to_datetime(x)
df = (df2.merge(df1.unstack(), left_index=True, right_index=True).sort_index(axis=1))

但我得到一个错误:

ValueError:无法合并没有名称的系列

我的错误是什么?

我的目标是每周添加从 df2df1 的列,这样 df1 将有 3 列而不是 2 列。

使用后

c = [df2.columns.map(date_mappings.get), df2.columns]
df1.join(df2.set_axis(c, axis=1)).sort_index(axis=1)

我将值附加到数据框的末尾,而不是附加到具有同一周命名的同一列:

这可能是一个问题,df2 持有来自2021-06-28 to 2022-06-27 的日期,而df1 持有来自2020 to today 的日期。

不需要添加到df 的末尾

【问题讨论】:

    标签: python pandas merge


    【解决方案1】:

    想法是在两个 DataFrames 中创建 MultiIndex:

    date_mappings = {
    1 : '2021-06-28',
    2 : '2021-07-05'}
    
    #create MultiIndex in df2 with datetimes in first level
    df2.columns = pd.MultiIndex.from_product([pd.to_datetime(df2.columns.map(date_mappings)), 
                                              ['metric_3']])
    
    #removed unused levels, here category, so possible convert first leve to datetimes
    df1.columns = df1.columns.remove_unused_levels()
    df1.columns = df1.columns.set_levels(pd.to_datetime(df1.columns.levels[0]), level=0)
    
    #join together and sorting MultiIndex
    df = df1.join(df2).sort_index(axis=1)
    

    print (df)
                2021-06-28                             2021-07-05            \
                  metric_1  metric_2       metric_3      metric_1  metric_2   
    category                                                                  
    A          4120.550000   9907.79   36234.035578   5817.320000   6321.21   
    B         11226.016667   7614.65   69078.070892  10799.450000   5606.01   
    C         25049.443333  13775.26  128879.539752  23521.510000  10239.69   
    D         18261.083333  13158.25  178376.635369  22062.350833  17476.60   
    E          2553.120833   1457.85    9293.956915   1249.597500    943.72   
    F          2843.010000   1089.56    8184.780211   3229.770000   1410.33   
    G         73203.513333  38864.90  177480.745403  52796.060833  29645.45   
    
                             
                   metric_3  
    category                 
    A          37887.581678  
    B          72243.679562  
    C         134803.023421  
    D         186603.896317  
    E           9716.385738  
    F           8555.606694  
    G         185658.875780  
    

    如果需要删除更大的日期时间,例如最大 df1 日期时间使用:

    #change mapping for test
    date_mappings = {
    1 : '2021-06-28',
    2 : '2022-07-05'}
    
    df2.columns = pd.MultiIndex.from_product([pd.to_datetime(df2.columns.map(date_mappings)), 
                                              ['metric_3']])
    
    df1.columns = df1.columns.remove_unused_levels()
    df1.columns = df1.columns.set_levels(pd.to_datetime(df1.columns.levels[0]), level=0)
    
    
    df2 = df2.loc[:, df2.columns.get_level_values(0) <= df1.columns.get_level_values(0).max()]
    print (df2)
                 2021-06-28
                   metric_3
    category               
    A          36234.035578
    B          69078.070892
    C         128879.539752
    D         178376.635369
    E           9293.956915
    F           8184.780211
    G         177480.745403
    
    #join together and sorting MultiIndex
    df = df1.join(df2).sort_index(axis=1)
    

    print (df)
                2021-06-28                             2021-07-05          
                  metric_1  metric_2       metric_3      metric_1  metric_2
    category                                                               
    A          4120.550000   9907.79   36234.035578   5817.320000   6321.21
    B         11226.016667   7614.65   69078.070892  10799.450000   5606.01
    C         25049.443333  13775.26  128879.539752  23521.510000  10239.69
    D         18261.083333  13158.25  178376.635369  22062.350833  17476.60
    E          2553.120833   1457.85    9293.956915   1249.597500    943.72
    F          2843.010000   1089.56    8184.780211   3229.770000   1410.33
    G         73203.513333  38864.90  177480.745403  52796.060833  29645.45
    

    【讨论】:

    • @JonasPalačionis - df1 中有日期时间吗?你用df1.columns = df1.columns.remove_unused_levels() df1.columns = df1.columns.set_levels(pd.to_datetime(df1.columns.levels[0]), level=0) 吗?
    • @JonasPalačionis - 所以删除了更大的日期时间?
    • 是的,这就是目标
    • @JonasPalačionis - 添加到答案中,快乐编码! ;)
    • 再次感谢您,先生!
    【解决方案2】:

    使用pd.DataFrame.reindex + pd.DataFrame.join reindex 有一个方便的级别参数,允许您扩展不存在的索引级别。

    df1.join(df2.reindex(df1.index, level=0))
    

    【讨论】:

      【解决方案3】:

      我不确定这是否是您想要的,但您可能需要to_frame

      f = lambda x: pd.to_datetime(x)
      df = (df2.merge(df1.unstack().to_frame(), left_index=True, right_index=True).sort_index(level=0))
      print(df)
      

      【讨论】:

      • 我试图保持df1 的格式,并且只在每个匹配的周添加来自df2 的列。我认为这与我的 df2 没有它所持有的值的列/系列名称有关。
      猜你喜欢
      • 2018-03-15
      • 2021-12-04
      • 2017-03-20
      • 2020-10-05
      • 1970-01-01
      • 1970-01-01
      • 2012-11-25
      • 2015-10-28
      相关资源
      最近更新 更多