堆栈熊猫数据框

时间:2021-03-05 13:24:45

标签: python pandas pandas-melt

我有一个数据框需要堆叠、融合或旋转。对于每所学校,我需要为每个容量创建一个新行,以及一个新的级别列。级别取决于容量是否 > 0。还应包括城市列:

data = pd.DataFrame({'school_name': {0: 'a', 1: 'b', 2: 'c'},
                     'primary': {0: 1, 1: 3, 2: 0},
                     'secondary': {0: 2, 1: 0, 2: 6},
                     'tertiary': {0:3, 1:6, 2:0},
                     'city': {0:'Bangkok', 1:'Frankfurt', 2:'Tel Aviv'}})
data

  school_name  primary  secondary  tertiary       city
0           a        1          2         3    Bangkok
1           b        3          0         6  Frankfurt
2           c        0          6         0   Tel Aviv

想要的结果:

    school_name levels     capacity    city
0   a           primary     1          Bangkok
1   a           secondary   2          Bangkok
2   a           tertiary    3          Bangkok
3   b           primary     3          Frankfurt
4   b           tertiary    6          Frankfurt
5   c           secondary   6          Tel Aviv

4 个答案:

答案 0 :(得分:2)

让我们 stack 在屏蔽 0primarysecondary 列中的 tertiary 值后重塑数据框:

df = data.set_index(['school_name', 'city'])
df = df[df.ne(0)].stack().reset_index(name='capacity')\
                 .rename(columns={'level_2': 'levels'})

>>> df

  school_name       city     levels   capacity
0           a    Bangkok    primary       1.0
1           a    Bangkok  secondary       2.0
2           a    Bangkok   tertiary       3.0
3           b  Frankfurt    primary       3.0
4           b  Frankfurt   tertiary       6.0
5           c   Tel Aviv  secondary       6.0

答案 1 :(得分:2)

在过滤大于 0 的行之前,您可以使用 pivot_longer 中的 pyjanitor 来重塑数据:

 import janitor

(df
 .pivot_longer(index=['school_name', 'city'], 
               names_to=("levels", ".value"), 
               names_sep="_")
 .query("capacity > 0")
 )


  school_name       city     levels  capacity
0           a    Bangkok    primary         1
1           b  Frankfurt    primary         3
3           a    Bangkok  secondary         2
5           c   Tel Aviv  secondary         6
6           a    Bangkok   tertiary         3
7           b  Frankfurt   tertiary         6

您也可以使用熊猫的wide_to_long

temp = df.rename(columns= lambda x: "_".join(x.split("_")[::-1])
                          if 'capacity' in x 
                          else x)

(pd.wide_to_long(temp, 
                 'capacity', 
                 ['school_name', 'city'], 
                 "levels", 
                  "_",
                  ".+")
   .query('capacity > 0').reset_index()
  )

  school_name       city     levels  capacity
0           a    Bangkok    primary         1
1           a    Bangkok  secondary         2
2           a    Bangkok   tertiary         3
3           b  Frankfurt    primary         3
4           b  Frankfurt   tertiary         6
5           c   Tel Aviv  secondary         6

您的问题已被编辑,所以这个答案应该足够了:

(data.melt(['school_name', 'city'], 
           var_name='levels', 
           value_name='capacity')
    .query('capacity > 0'))

  school_name       city     levels  capacity
0           a    Bangkok    primary         1
1           b  Frankfurt    primary         3
3           a    Bangkok  secondary         2
5           c   Tel Aviv  secondary         6
6           a    Bangkok   tertiary         3
7           b  Frankfurt   tertiary         6

答案 2 :(得分:2)

我会用 nan 替换 0 值,因为我知道这意味着该功能不存在

data2 = data.replace(0, np.nan)

然后融化我认为是你需要的。 (并删除 nan 值)

data2.melt(id_vars= ['school_name', 'city'], value_vars=['primary', 'secondary', 'tertiary']).dropna()

   school_name  city        variable    value
0   a           Bangkok     primary     1.0
1   b           Frankfurt   primary     3.0
3   a           Bangkok     secondary   2.0
5   c           Tel Aviv    secondary   6.0
6   a           Bangkok     tertiary    3.0
7   b           Frankfurt   tertiary    6.0

如果您不喜欢索引,请重置它们

data2.melt(id_vars= ['school_name', 'city'], value_vars=['primary', 'secondary', 'tertiary']).dropna().reset_index()

答案 3 :(得分:0)

# keep columns in index
data = data.set_index(["school_name","city"])
# remaining columns, name the index
data.columns.set_names("levels",inplace=True)
# simple stack and reset index
data.stack().reset_index()

<头>
学校名称 城市 levels 0
0 a 曼谷 主要 1
1 a 曼谷 次要 2
2 a 曼谷 第三级 3
3 b 法兰克福 主要 3
4 b 法兰克福 次要 0
5 b 法兰克福 第三级 6
6 c 特拉维夫 主要 0
7 c 特拉维夫 次要 6
8 c 特拉维夫 第三级 0