Pandas:如何将行添加到具有多索引的DataFrame中?

8

我有一个带有多级索引的DataFrame,想要使用字典来添加新行。

假设DataFrame中的每一行都是一个城市。列包含“距离”和“车辆”。每个单元格将是选择该车辆行驶该距离的人口百分比。

我正在构建这样的索引:

index_tuples=[]

for distance in ["near", "far"]:
    for vehicle in ["bike", "car"]:
        index_tuples.append([distance, vehicle])

index = pd.MultiIndex.from_tuples(index_tuples, names=["distance", "vehicle"])

然后我创建一个数据框:

dataframe = pd.DataFrame(index=["city"], columns = index)

数据框的结构看起来不错。虽然pandas已经添加了NaN作为默认值?

layout of the dataframe

现在我想为这个新城市设置一个字典,并将其添加进去:
my_home_city = {"near":{"bike":1, "car":0},"far":{"bike":0, "car":1}}
dataframe["my_home_city"] = my_home_city

但是这个操作失败了:

ValueError: 值的长度与索引的长度不匹配

这里是完整的error message(pastebin)

更新:

感谢所有好的回答。恐怕我在示例中过于简化了问题。实际上,我的索引嵌套了3个级别(并且可能会变得更多)。

因此,我接受了将字典转换为元组列表的通用答案。这可能不像其他方法那样干净,但适用于任何多重索引设置。


我认为字典的键需要是元组,例如{('near', 'bike'): 1, ('near', 'car'): 0 ...} - Paul H
附注:请查看 pandas.MultiIndex.from_product - Paul H
6个回答

4
您可以像这样向您的数据框添加内容:
my_home_city = {"near":{"bike":1, "car":0},"far":{"bike":0, "car":1}}
dataframe.append(pd.DataFrame.from_dict(my_home_city).unstack().rename('my_home_city'))

输出:

distance     near       far     
vehicle      bike  car bike  car
city          NaN  NaN  NaN  NaN
my_home_city    1    0    0    1

技巧在于使用from_dict创建数据帧行,然后使用unstack获取具有多索引列的原始数据框架结构,然后使用rename获取索引并使用append添加。或者,如果您不想先创建空数据帧,则可以使用此方法创建包含新数据的数据帧。
pd.DataFrame.from_dict(my_home_city).unstack().rename('my_home_city').to_frame().T

输出:

              far     near    
             bike car bike car
my_home_city    0   1    1   0

解释:

pd.DataFrame.from_dict(my_home_city)

      far  near
bike    0     1
car     1     0

现在,让我们进行unstack操作以创建MultiIndex,并将新的Dataframe结构化到原始Dataframe中。

pd.DataFrame.from_dict(my_home_city).unstack()

far   bike    0
      car     1
near  bike    1
      car     0
dtype: int64

我们使用rename命令给该系列起一个名称,当附加到原始数据帧时,该名称成为该数据帧行的索引标签。
far   bike    0
      car     1
near  bike    1
      car     0
Name: my_home_city, dtype: int64

现在,如果你将该系列转换为一个框架并进行转置,它看起来非常像一个新行,但是没有必要这样做,因为Pandas具有内在的数据对齐功能,因此将此系列附加到数据框中将自动对齐并添加新的数据框记录。
dataframe.append(pd.DataFrame.from_dict(my_home_city).unstack().rename('my_home_city'))
distance     near       far     
vehicle      bike  car bike  car
city          NaN  NaN  NaN  NaN
my_home_city    1    0    0    1

4

多级索引是一个元组列表,我们只需要修改您的字典,然后就可以直接赋值了。

d = {(x,y):my_home_city[x][y] for x in my_home_city for y in my_home_city[x]}
df.loc['my_home_city',:]=d
df
Out[994]: 
distance     near       far     
vehicle      bike  car bike  car
city          NaN  NaN  NaN  NaN
my_home_city    1    0    0    1

更多信息
d
Out[995]: 
{('far', 'bike'): 0,
 ('far', 'car'): 1,
 ('near', 'bike'): 1,
 ('near', 'car'): 0}

df.columns.values
Out[996]: array([('near', 'bike'), ('near', 'car'), ('far', 'bike'), ('far', 'car')], dtype=object)

2

我认为你甚至不需要初始化一个空的数据框。使用你的d,我可以通过unstack和转置来得到你想要的输出:

pd.DataFrame(d).unstack().to_frame().T

   far     near    
  bike car bike car
0    0   1    1   0

1

使用MultiIndex.from_product初始化您的空数据框。

distances = ['near', 'far']
vehicles = ['bike', 'car']
df = pd.DataFrame([], columns=pd.MultiIndex.from_product([distances, vehicles]), 
                  index=pd.Index([], name='city'))

您的字典结果是一个方阵 (距离按车辆计算),因此需要对其进行解除堆叠(将会得到一个 Series),然后通过调用 (to_frame) 将其转换为一个数据框行,使用相应的城市名称并将列转置为行。
>>> df.append(pd.DataFrame(my_home_city).unstack().to_frame('my_home_city').T)
              far     near    
             bike car bike car
city                          
my_home_city    0   1    1   0

1

除了所有答案之外,这只是另一个(也许不太不同)简单的例子,以更可重复的方式表示:

import itertools as it
from IPython.display import display # this is just for displaying output purpose
import numpy as np
import pandas as pd

col_1, col_2 = ['A', 'B'], ['C', 'D']
arr_size = len(col_2)
col = pd.MultiIndex.from_product([col_1, col_2])
tmp_df = pd.DataFrame(columns=col)
display(tmp_df)

for s in range(3):# no of rows to add to tmp_df
    tmp_dict = {x : [np.random.random_sample(1)[0] for i in range(arr_size)] for x in range(arr_size)}
    tmp_ser = pd.Series(it.chain.from_iterable([tmp_dict[x] for x in tmp_dict]), index=col)
    #  display(tmp_dict, tmp_ser)
    tmp_df = tmp_df.append(tmp_ser[tmp_df.columns], ignore_index=True)

display(tmp_df)

以下是需要注意的一些事项:

  • 要添加的项目数量应始终与 len(col_1)*len(col_2) 相匹配,即您的多级索引由元素长度的乘积组成。
  • list(it.chain.from_iterable([[2, 3], [4, 5]])) 简单地将其转换为 [2,3,4,5]

0

尝试这个解决方法

  • 将数据附加到字典中
  • 然后将其转换为Pandas数据框
  • 在最后一步使用set_index()选择所需列以创建多级索引
d = dict()
for g in predictor_types:
    for col in predictor_types[g]:
        tot = len(ames) - ames[col].count()
        if tot:
            d.setdefault('type',[]).append(g)
            d.setdefault('predictor',[]).append(col)
            d.setdefault('missing',[]).append(tot)
pd.DataFrame(d).set_index(['type','predictor']).style.bar(color='DodgerBlue')

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接