Python 从现有数据帧构建分层索引数据帧

Python 从现有数据帧构建分层索引数据帧,python,pandas,Python,Pandas,我有两个具有相同列和索引的数据帧。我想将它们组合成第三个数据帧和一个层次索引,维护当前索引并添加第二个数据帧来标识每个数据帧的来源。这就是我所尝试的: df_a = pd.DataFrame(randn(3, 2), columns=["x", "y"], index=range(3)) df_b = pd.DataFrame(randn(3, 2), columns=["x", "y"], index=range(3)) tuples = list(itertools.product(["a"

我有两个具有相同列和索引的数据帧。我想将它们组合成第三个数据帧和一个层次索引,维护当前索引并添加第二个数据帧来标识每个数据帧的来源。这就是我所尝试的:

df_a = pd.DataFrame(randn(3, 2), columns=["x", "y"], index=range(3))
df_b = pd.DataFrame(randn(3, 2), columns=["x", "y"], index=range(3))
tuples = list(itertools.product(["a", "b"], range(3)))
df = pd.DataFrame(columns=["x", "y"], index=pd.MultiIndex.from_tuples(tuples))
df.loc["a"] = df_a
df.loc["b"] = df_b
然而,
df
仍然充满了
nan
,而我希望它会被
df_a
df_b
中的值填充。这确实有效:

>>> df_a = pd.DataFrame(randn(3, 2), columns=["x", "y"], index=range(3))
>>> df_b = pd.DataFrame(randn(3, 2), columns=["x", "y"], index=range(3))
>>> 
>>> tuples = list(itertools.product(["a", "b"], range(3)))
>>> df = pd.DataFrame(columns=["x", "y"], index=pd.MultiIndex.from_tuples(tuples))
>>> 
>>> df_a.index = pd.MultiIndex.from_tuples([tuple(('a', i)) for i in df_a.index])
>>> 
>>> df.ix["a"] = df_a
>>> df
             x          y
a 0   1.533881   1.276075
  1 -0.5143746 -0.3400633
  2  -1.071509   1.831282
b 0        NaN        NaN
  1        NaN        NaN
  2        NaN        NaN
但似乎既迂回又错误


关于层次索引,我不了解什么?实现我的目标的最佳方法是什么?

另一种方法是将多索引添加到原始数组(
df_a
df_b
)中,而不是填充数据帧

df未被填充的原因是pandas根据索引进行数据对齐。当为df.ix[“a”]分配另一个数据帧时,它会填充索引匹配的值。为了说明这一点:

>>> df = pd.DataFrame(randn(3, 2), columns=["x", "y"], index=range(3))
>>> df2 = pd.DataFrame(zeros((1, 2)), columns=["x", "y"], index=range(2,3))
>>> df
          x         y
0 -0.995116  0.132438
1 -0.023010 -0.211612
2 -0.053206  0.427369
>>> df2
   x  y
2  0  0
>>> df.ix[:] = df2
>>> df
    x   y
0 NaN NaN
1 NaN NaN
2   0   0
当分配numpy数组(或列表,…)时,没有要匹配的索引,因此它只填充数据帧(在本例中还进行广播):

因此,在您的情况下,当您尝试将
df_a
分配给
df.ix['a']
时,索引不匹配(多索引与普通索引),并且没有分配任何内容(或者更准确地说:用NaN填充)。但是,当您第一次将
df_a
转换为具有相同的多索引时,它确实起作用:

>>> df_a = pd.DataFrame(randn(3, 2), columns=["x", "y"], index=range(3))
>>> df_b = pd.DataFrame(randn(3, 2), columns=["x", "y"], index=range(3))
>>> 
>>> tuples = list(itertools.product(["a", "b"], range(3)))
>>> df = pd.DataFrame(columns=["x", "y"], index=pd.MultiIndex.from_tuples(tuples))
>>> 
>>> df_a.index = pd.MultiIndex.from_tuples([tuple(('a', i)) for i in df_a.index])
>>> 
>>> df.ix["a"] = df_a
>>> df
             x          y
a 0   1.533881   1.276075
  1 -0.5143746 -0.3400633
  2  -1.071509   1.831282
b 0        NaN        NaN
  1        NaN        NaN
  2        NaN        NaN
或者如上所述,当使用numpy数组(属性
.values
将数据作为numpy数组返回)时,它也可以工作:

>>> df.ix["b"] = df_b.values
>>> df
               x          y
a 0     1.533881   1.276075
  1   -0.5143746 -0.3400633
  2    -1.071509   1.831282
b 0   0.06535034 -0.6276186
  1  0.008100781  0.9512881
  2   0.08688541 -0.7101486

但是我认为,实现这一点的另一种方法是将多索引添加到原始数组中,然后将它们连接起来,而不是填充数据帧
df

要将其转换为多索引,可以按如下方式执行:

>>> df_a['df'] = 'a'
>>> df_b['df'] = 'b'
>>> 
>>> df_a = df_a.set_index('df', append=True)
>>> df_b = df_b.set_index('df', append=True)
>>> df_a.index = pd.MultiIndex.from_tuples([tuple(('a', i)) for i in df_a.index])
>>> df_b.index = pd.MultiIndex.from_tuples([tuple(('b', i)) for i in df_b.index])
或者像这样:

>>> df_a['df'] = 'a'
>>> df_b['df'] = 'b'
>>> 
>>> df_a = df_a.set_index('df', append=True)
>>> df_b = df_b.set_index('df', append=True)
>>> df_a.index = pd.MultiIndex.from_tuples([tuple(('a', i)) for i in df_a.index])
>>> df_b.index = pd.MultiIndex.from_tuples([tuple(('b', i)) for i in df_b.index])
然后可以将它们连接起来:

>>> df = pd.concat([df_a, df_b])
>>> df
             x         y
  df                    
0 a  -0.225156 -0.846229
1 a   1.566139  0.892763
2 a  -1.291920 -0.517408
0 b   1.464853  0.792709
1 b  -1.307375 -0.360373
2 b   0.467406  1.249325
>>> 
>>> df.swaplevel(0,1)
             x         y
df                      
a  0 -0.225156 -0.846229
   1  1.566139  0.892763
   2 -1.291920 -0.517408
b  0  1.464853  0.792709
   1 -1.307375 -0.360373
   2  0.467406  1.249325