【问题标题】:Lengthening a DataFrame based on stacking columns within it in Pandas根据 Pandas 中的堆叠列来延长 DataFrame
【发布时间】:2018-11-02 00:43:25
【问题描述】:

我正在寻找实现以下功能的功能。最好用一个例子来说明。考虑:

pd.DataFrame([ [1, 2, 3 ], [4, 5, np.nan ]], columns=['x', 'y1', 'y2'])

看起来像:

   x  y1   y2
0  1   2  3
1  4   5  NaN

我想折叠 y1y2 列,在必要时延长 DataFame,以便输出为:

   x  y
0  1   2  
1  1   3  
2  4   5  

也就是说,xy1xy2 之间的每个组合对应一行。我正在寻找一个相对有效的函数,因为我有多个 ys 和很多行。

【问题讨论】:

  • 如果x 值之一是 NaN 怎么办?
  • @Kasramvd 有趣的问题,但在我的应用程序中没有发生
  • 我想在这种情况下最自然的是以同样的方式重复 nan

标签: python python-3.x pandas numpy dataframe


【解决方案1】:

根据每行中非空值的计数重复第一列中的所有项目。然后只需使用其他列中其余的非空值创建您的最终数据框。您可以使用DataFrame.count() 方法对非空值进行计数,并使用numpy.repeat() 根据相应的计数数组重复一个数组。

>>> rest = df.loc[:,'y1':]
>>> pd.DataFrame({'x': np.repeat(df['x'], rest.count(1)).values,
                  'y': rest.values[rest.notna()]})

演示:

>>> df
    x   y1   y2   y3   y4
0   1  2.0  3.0  NaN  6.0
1   4  5.0  NaN  9.0  3.0
2  10  NaN  NaN  NaN  NaN
3   9  NaN  NaN  6.0  NaN
4   7  6.0  NaN  NaN  NaN

>>> rest = df.loc[:,'y1':]
>>> pd.DataFrame({'x': np.repeat(df['x'], rest.count(1)).values,
                  'y': rest.values[rest.notna()]})
   x    y
0  1  2.0
1  1  3.0
2  1  6.0
3  4  5.0
4  4  9.0
5  4  3.0
6  9  6.0
7  7  6.0

【讨论】:

    【解决方案2】:

    您可以使用stack 来完成工作,即

    pd.DataFrame(df.set_index('x').stack().reset_index(level=0).values,columns=['x','y'])
    
         x    y
    0  1.0  2.0
    1  1.0  3.0
    2  4.0  5.0
    

    【讨论】:

      【解决方案3】:

      这是一个基于 NumPy 的,因为您正在寻找性能 -

      def gather_columns(df):
          col_mask = [i.startswith('y') for i in df.columns]
          ally_vals = df.iloc[:,col_mask].values
          y_valid_mask = ~np.isnan(ally_vals)
      
          reps = np.count_nonzero(y_valid_mask, axis=1)
          x_vals = np.repeat(df.x.values, reps)
          y_vals = ally_vals[y_valid_mask]
          return pd.DataFrame({'x':x_vals, 'y':y_vals})
      

      示例运行 -

      In [78]: df #(added more cols for variety)
      Out[78]: 
         x  y1   y2   y5   y7
      0  1   2  3.0  NaN  NaN
      1  4   5  NaN  6.0  7.0
      
      In [79]: gather_columns(df)
      Out[79]: 
         x    y
      0  1  2.0
      1  1  3.0
      2  4  5.0
      3  4  6.0
      4  4  7.0
      

      如果y 列总是从第二列开始直到结束,我们可以简单地对数据帧进行切片,从而进一步提高性能,就像这样 -

      def gather_columns_v2(df):
          ally_vals = df.iloc[:,1:].values
          y_valid_mask = ~np.isnan(ally_vals)
      
          reps = np.count_nonzero(y_valid_mask, axis=1)
          x_vals = np.repeat(df.x.values, reps)
          y_vals = ally_vals[y_valid_mask]
          return pd.DataFrame({'x':x_vals, 'y':y_vals})
      

      【讨论】:

        猜你喜欢
        • 2018-04-12
        • 2016-03-26
        • 2016-11-02
        • 2019-12-10
        • 1970-01-01
        • 1970-01-01
        • 2022-01-19
        相关资源
        最近更新 更多