【问题标题】:Pandas element-wise min max against a series along one axisPandas element-wise min max 针对沿一个轴的系列
【发布时间】:2017-10-16 04:23:26
【问题描述】:

我有一个数据框:

df = 
             A    B    C    D
DATA_DATE
20170103   5.0  3.0  NaN  NaN
20170104   NaN  NaN  NaN  1.0
20170105   1.0  NaN  2.0  3.0

我有一个系列

s = 
DATA_DATE
20170103    4.0
20170104    0.0
20170105    2.2

我想运行一个元素方面的max() 函数,并沿着df 的列对齐s。换句话说,我想得到

result = 
             A    B    C    D
DATA_DATE
20170103   5.0  4.0  NaN  NaN
20170104   NaN  NaN  NaN  1.0
20170105   2.2  NaN  2.2  3.0

最好的方法是什么?我检查了single column comparisonseries to series comparison,但还没有找到一种有效的方法来针对一系列运行数据帧。

奖励:不确定上面的答案是否不言而喻,但是如果我想将sdf 对齐,该怎么做(假设尺寸匹配) ?

【问题讨论】:

    标签: pandas dataframe max min elementwise-operations


    【解决方案1】:

    数据:

    In [135]: df
    Out[135]:
                 A    B    C    D
    DATA_DATE
    20170103   5.0  3.0  NaN  NaN
    20170104   NaN  NaN  NaN  1.0
    20170105   1.0  NaN  2.0  3.0
    
    In [136]: s
    Out[136]:
    20170103    4.0
    20170104    0.0
    20170105    2.2
    Name: DATA_DATE, dtype: float64
    

    解决方案:

    In [66]: df.clip_lower(s, axis=0)
    C:\Users\Max\Anaconda4\lib\site-packages\pandas\core\ops.py:1247: RuntimeWarning: invalid value encountered in greater_equal
      result = op(x, y)
    Out[66]:
                 A    B    C    D
    DATA_DATE
    20170103   5.0  4.0  NaN  NaN
    20170104   NaN  NaN  NaN  1.0
    20170105   2.2  NaN  2.2  3.0
    

    我们可以使用以下 hack 来摆脱 RuntimeWarning

    In [134]: df.fillna(np.inf).clip_lower(s, axis=0).replace(np.inf, np.nan)
    Out[134]:
                 A    B    C    D
    DATA_DATE
    20170103   5.0  4.0  NaN  NaN
    20170104   NaN  NaN  NaN  1.0
    20170105   2.2  NaN  2.2  3.0
    

    【讨论】:

    • 干净多了。 :)
    • 我正在尝试重现答案,但我得到了一堆 Nan 值。知道我做错了什么吗?
    • 要完成答案,显然要对齐第一行只需要设置axis=1。正如@MaxU 前面提到的,确保 DataFrame 和 Series 之间的索引和列名匹配对于此工作非常重要。
    • @Zhang18,我认为是因为 NaN。你可以试试这个肮脏的黑客:df.fillna(np.inf).clip_lower(s, axis=0).replace(np.inf, np.nan)
    • 只要至少有一列没有NaN,那么clip_lower 就不会在整个操作中抛出错误。感觉是个bug。我会尝试在 GitHub 上提交问题请求。
    【解决方案2】:

    这称为广播,可以按如下方式进行:

    import numpy as np
    np.maximum(df, s[:, None])
    Out: 
                 A    B    C    D
    DATA_DATE                    
    20170103   5.0  4.0  NaN  NaN
    20170104   NaN  NaN  NaN  1.0
    20170105   2.2  NaN  2.2  3.0
    

    在这里,s[:, None] 将向s 添加一个新轴。 s[:, np.newaxis] 也可以达到同样的效果。当你这样做时,它们可以一起广播,因为形状 (3, 4)(3, 1) 有一个共同的元素。

    注意ss[:, None]的区别:

    s.values
    Out: array([ 4. ,  0. ,  2.2])
    
    s[:, None]
    Out: 
    array([[ 4. ],
           [ 0. ],
           [ 2.2]])
    
    s.shape
    Out: (3,)
    
    s[:, None].shape
    Out: (3, 1)
    

    另一种选择是:

    df.mask(df.le(s, axis=0), s, axis=0)
    
    Out: 
                 A    B    C    D
    DATA_DATE                    
    20170103   5.0  4.0  NaN  NaN
    20170104   NaN  NaN  NaN  1.0
    20170105   2.2  NaN  2.2  3.0
    

    内容如下:比较 df 和 s。如果 df 较大,则使用 df,否则使用 s。

    【讨论】:

    • 不要卖空@ayhan,这是一个很好的答案。了解广播和比较系列与数据帧。谢谢!
    • @pshep123 谢谢。 :)
    【解决方案3】:

    虽然您的问题可能有更好的解决方案,但我相信这应该可以满足您的需求:

    for c in df.columns:
        df[c] = pd.concat([df[c], s], axis=1).max(axis=1)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-09-30
      • 1970-01-01
      • 2012-10-10
      • 2014-04-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多