【问题标题】:Using the last valid data index in one Dataframe to select data in another Dataframe使用一个 Dataframe 中的最后一个有效数据索引来选择另一个 Dataframe 中的数据
【发布时间】:2020-12-14 10:29:43
【问题描述】:

我想找到第一个 Dataframe 的最后一个有效索引,并用它来索引第二个 Dataframe。

所以,假设我有以下 Dataframe (df1):

            Site 1  Site 2  Site 3  Site 4  Site 5  Site 6
Date                                                      
2000-01-01    13.0    28.0    76.0      45    90.0    58.0
2001-01-01    77.0    75.0    57.0       3    41.0    24.0
2002-01-01    50.0    29.0     2.0      65    48.0    21.0
2003-01-01     7.0    48.0    14.0      63    12.0    66.0
2004-01-01    11.0    90.0    11.0       5    47.0     6.0
2005-01-01    50.0     4.0    31.0       1    40.0    79.0
2006-01-01    30.0    98.0    91.0      96    43.0    39.0
2007-01-01    50.0    20.0    54.0      65     NaN    47.0
2008-01-01    24.0    84.0    52.0      84     NaN    81.0
2009-01-01    56.0    61.0    57.0      25     NaN    36.0
2010-01-01    87.0    45.0    68.0      65     NaN    71.0
2011-01-01    22.0    50.0    92.0      91     NaN    48.0
2012-01-01    12.0    44.0    79.0      77     NaN    25.0
2013-01-01     1.0    22.0    34.0      57     NaN    25.0
2014-01-01    94.0     NaN    86.0      97     NaN    91.0
2015-01-01     2.0     NaN    98.0      44     NaN    79.0
2016-01-01    81.0     NaN    35.0      87     NaN    32.0
2017-01-01    59.0     NaN    95.0      32     NaN    58.0
2018-01-01     NaN     NaN     3.0      14     NaN     NaN
2019-01-01     NaN     NaN    48.0       9     NaN     NaN
2020-01-01     NaN     NaN     NaN      49     NaN     NaN

现在我可以使用“first_valid_index()”来查找每列的最后一个有效索引:

lvi = df.apply(lambda series: series.last_valid_index())

产量:

Site 1   2017-01-01
Site 2   2013-01-01
Site 3   2019-01-01
Site 4   2020-01-01
Site 5   2006-01-01
Site 6   2017-01-01

我如何将它应用到另一个 Dataframe,我使用这个索引来切片另一个 Dataframe 的时间序列。可以使用以下方法创建另一个 Dataframe 示例:

import pandas as pd
import numpy as np
from numpy import random

random.seed(30)

df2 = pd.DataFrame({
    "Site 1": np.random.rand(21),
    "Site 2": np.random.rand(21),
    "Site 3": np.random.rand(21),
    "Site 4": np.random.rand(21),
    "Site 5": np.random.rand(21),
    "Site 6": np.random.rand(21)})

idx = pd.date_range(start='2000-01-01', end='2020-01-01',freq ='AS')
df2 = df2.set_index(idx)

如何使用“lvi”变量来索引 df2?

要手动执行此操作,我可以使用:

df_s1 = df['Site 1'].loc['2000-01-01':'2017-01-01']

得到类似的东西:

2000-01-01    13.0
2001-01-01    77.0
2002-01-01    50.0
2003-01-01     7.0
2004-01-01    11.0
2005-01-01    50.0
2006-01-01    30.0
2007-01-01    50.0
2008-01-01    24.0
2009-01-01    56.0
2010-01-01    87.0
2011-01-01    22.0
2012-01-01    12.0
2013-01-01     1.0
2014-01-01    94.0
2015-01-01     2.0
2016-01-01    81.0
2017-01-01    59.0

有没有更好的方法来解决这个问题?此外,每一列是否必须本质上是它自己的数据框才能工作?非常感谢任何帮助!

【问题讨论】:

  • 不像df.index.max()那么简单?

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


【解决方案1】:

这似乎工作得很好:

In [34]: d
Out[34]: 
      x    y
Date                
2020-01-01  1.0  2.0
2020-01-02  1.0  2.0
2020-01-03  1.0  2.0
2020-01-04  1.0  2.0
2020-01-05  1.0  2.0
2020-01-06  1.0  NaN
2020-01-07  1.0  NaN
2020-01-08  1.0  NaN
2020-01-09  1.0  NaN
2020-01-10  1.0  NaN
2020-01-11  NaN  NaN
2020-01-12  NaN  NaN
2020-01-13  NaN  NaN
2020-01-14  NaN  NaN
2020-01-15  NaN  NaN
2020-01-16  NaN  NaN
2020-01-17  NaN  NaN
2020-01-18  NaN  NaN
2020-01-19  NaN  NaN
2020-01-20  NaN  NaN

In [35]: d.apply(lambda col: col.last_valid_index())
Out[35]: 
x   2020-01-10
y   2020-01-05
dtype: datetime64[ns]

然后: In [15]: d.apply(lambda col: col.last_valid_index()).apply(lambda date: df2.loc[date]) Out[15]: z x 0.940396 y 0.564007

【讨论】:

  • 嗨罗比,谢谢你的回答。所以现在你已经到了这一步,我的问题的另一部分是你如何将你在这里得到的 last_valid_index 值应用到另一个数据帧?因此,假设您有另一个数据帧 (df2),其中 x2 和 y2 在同一时间跨度内始终具有有效数据。我只希望 df2 中的数据反映数据,直到 df1 的最后一个有效索引。这有意义吗?
  • 我添加了一个部分来处理这个问题。只是另一个apply,并使用.loc[] 功能。
  • 嗨罗比,感谢您的反馈。我希望输出是 df2 的一部分。所以在我的例子中,我的预期输出从 2000 年到 2017 年(由 df['Site 1'].loc['2000-01-01':'2017-01-01'] 给出)这样你就有了更多的上下文本练习的要点:我正在使用最后一个有效索引,并且我将计算 df2 中每一列的最后一个有效数据点的时间变化百分比。我最终试图纠正数据在 df1 的每一列中结束时的差异,并将它们投影到 df2 上以获得我的 % 更改。我希望这有点道理......
  • 我认为你有一个好的开始。在 Pandas 中总是有几种方法可以做这种事情。
  • 很好,感谢罗比的帮助!
【解决方案2】:

好的,所以在考虑了一段时间并试图提出一个涉及 for 循环等的详细过程之后,我得出的结论是这个简单的数学运算可以解决问题。基本上,我正在利用 Pandas 中 Dataframe 之间的数学运算方式。

output = df1*0 + df2

这给出了 df2 上的输出,它将采用 df1 中的 NaN 值,如下所示:

              Site 1    Site 2    Site 3    Site 4    Site 5    Site 6
Date                                                                  
2000-01-01  0.690597  0.443933  0.787931  0.659639  0.363606  0.922373
2001-01-01  0.388669  0.577734  0.450225  0.021592  0.554249  0.305546
2002-01-01  0.578212  0.927848  0.361426  0.840541  0.626881  0.545491
2003-01-01  0.431668  0.128282  0.893351  0.783488  0.122182  0.666194
2004-01-01  0.151491  0.928584  0.834474  0.945401  0.590830  0.802648
2005-01-01  0.113477  0.398326  0.649955  0.202538  0.485927  0.127925
2006-01-01  0.521906  0.458672  0.923632  0.948696  0.638754  0.552753
2007-01-01  0.266599  0.839047  0.099069  0.000928       NaN  0.018146
2008-01-01  0.819810  0.809779  0.706223  0.247780       NaN  0.759691
2009-01-01  0.441574  0.020291  0.702551  0.468862       NaN  0.341191
2010-01-01  0.277030  0.130573  0.906697  0.589474       NaN  0.819986
2011-01-01  0.795344  0.103121  0.846405  0.589916       NaN  0.564411
2012-01-01  0.697255  0.599767  0.206482  0.718980       NaN  0.731366
2013-01-01  0.891771  0.001944  0.703132  0.751986       NaN  0.845933
2014-01-01  0.672579       NaN  0.466981  0.466770       NaN  0.618069
2015-01-01  0.767219       NaN  0.702156  0.370905       NaN  0.481971
2016-01-01  0.315264       NaN  0.793531  0.754920       NaN  0.091432
2017-01-01  0.431651       NaN  0.974520  0.708074       NaN  0.870077
2018-01-01       NaN       NaN  0.408743  0.430576       NaN       NaN
2019-01-01       NaN       NaN  0.751509  0.755521       NaN       NaN
2020-01-01       NaN       NaN       NaN  0.518533       NaN       NaN

我基本上是想将 NaN 值从一个 Dataframe 印到另一个 Dataframe 上。我无法相信我做这件事有多困难。只要我的数据框大小相同,就可以满足我的需求。

现在我应该能够从这里计算每个最后一个有效数据点的百分比变化。谢谢大家的意见!

编辑:

只是为了向大家展示我最终想要完成的工作,这是我在大家的帮助和建议下生成的最终代码!

原来的df原来是这样的:

            Site 1  Site 2  Site 3  Site 4  Site 5  Site 6
Date                                                      
2000-01-01    13.0    28.0    76.0      45    90.0    58.0
2001-01-01    77.0    75.0    57.0       3    41.0    24.0
2002-01-01    50.0    29.0     2.0      65    48.0    21.0
2003-01-01     7.0    48.0    14.0      63    12.0    66.0
2004-01-01    11.0    90.0    11.0       5    47.0     6.0
2005-01-01    50.0     4.0    31.0       1    40.0    79.0
2006-01-01    30.0    98.0    91.0      96    43.0    39.0
2007-01-01    50.0    20.0    54.0      65     NaN    47.0
2008-01-01    24.0    84.0    52.0      84     NaN    81.0
2009-01-01    56.0    61.0    57.0      25     NaN    36.0
2010-01-01    87.0    45.0    68.0      65     NaN    71.0
2011-01-01    22.0    50.0    92.0      91     NaN    48.0
2012-01-01    12.0    44.0    79.0      77     NaN    25.0
2013-01-01     1.0    22.0    34.0      57     NaN    25.0
2014-01-01    94.0     NaN    86.0      97     NaN    91.0
2015-01-01     2.0     NaN    98.0      44     NaN    79.0
2016-01-01    81.0     NaN    35.0      87     NaN    32.0
2017-01-01    59.0     NaN    95.0      32     NaN    58.0
2018-01-01     NaN     NaN     3.0      14     NaN     NaN
2019-01-01     NaN     NaN    48.0       9     NaN     NaN
2020-01-01     NaN     NaN     NaN      49     NaN     NaN

然后我想出了第二个完整的数据帧(df2):

df2 = pd.DataFrame({
    "Site 1": np.random.rand(21),
    "Site 2": np.random.rand(21),
    "Site 3": np.random.rand(21),
    "Site 4": np.random.rand(21),
    "Site 5": np.random.rand(21),
    "Site 6": np.random.rand(21)})
idx = pd.date_range(start='2000-01-01', end='2020-01-01',freq ='AS')
df2 = df2.set_index(idx)

现在我将 df2 中的 nan 值替换为 df 中的 nan 值:

dfr = df2[df.notna()]

然后我反转数据框:

dfr = dfr[::-1]

valid_first = dfr.apply(lambda col: col.first_valid_index())
valid_last = dfr.apply(lambda col: col.last_valid_index())

现在我想要计算我最后一个有效数据点的百分比变化,该数据点对于每一列都是固定的。这给了我从现在到过去的百分比变化,相对于最近的(或最后一个有效的)数据点。

new = []
for j in dfr:
    m = dfr[j].loc[valid_first[j]:valid_last[j]]
    pc = m / m.iloc[0]-1
    new.append(pc)

final = pd.concat(new,axis=1)    
print(final) 

这给了我:

              Site 1    Site 2    Site 3    Site 4     Site 5    Site 6
2000-01-01  0.270209 -0.728445 -0.636105  0.380330  41.339081 -0.462147
2001-01-01  0.854952 -0.827804 -0.703568 -0.787391  40.588791 -0.884806
2002-01-01 -0.677757 -0.120482 -0.208255 -0.982097  54.348094 -0.483415
2003-01-01 -0.322010 -0.061277 -0.382602  1.025088   5.440808 -0.602661
2004-01-01  1.574451 -0.768251 -0.543260  1.210434  50.494788 -0.859331
2005-01-01 -0.412226 -0.866441 -0.055027 -0.168267   1.346869 -0.385080
2006-01-01  1.280867 -0.640899  0.354513  1.086703   0.000000  0.108504
2007-01-01  1.121585 -0.741675 -0.735990 -0.768578        NaN -0.119436
2008-01-01 -0.210467 -0.376884 -0.575106 -0.779147        NaN  0.055949
2009-01-01  1.864107 -0.966827  0.566590  1.003121        NaN -0.214482
2010-01-01  0.571762 -0.311459 -0.518113  1.036950        NaN -0.513911
2011-01-01 -0.122525 -0.178137 -0.641642  0.197481        NaN  0.033141
2012-01-01  0.403578 -0.829402  0.161753 -0.438578        NaN -0.996595
2013-01-01  0.383481  0.000000 -0.305824  0.602079        NaN -0.057711
2014-01-01 -0.699708       NaN -0.515074 -0.277157        NaN -0.840873
2015-01-01  0.422364       NaN -0.759708  1.230037        NaN -0.663253
2016-01-01 -0.418945       NaN  0.197396 -0.445260        NaN -0.299741
2017-01-01  0.000000       NaN -0.897428  0.669791        NaN  0.000000
2018-01-01       NaN       NaN  0.138997  0.486961        NaN       NaN
2019-01-01       NaN       NaN  0.000000  0.200771        NaN       NaN
2020-01-01       NaN       NaN       NaN  0.000000        NaN       NaN 

我知道这些问题通常没有上下文,因此这里是您输入的最终输出。再次感谢大家的帮助!

【讨论】:

    【解决方案3】:

    这可能更惯用:

    df2[df.notna()]
    

    甚至

    df2.where(df.notna())
    

    请注意,在这些情况下(和df1*0 + df2),操作是为了匹配dfdf2 的索引值。例如,df2[df.reset_index(drop=True).notna()] 将返回所有 nan,因为没有公共索引值。

    【讨论】:

    • 您好,谢谢!我对 Python 有点陌生,所以绝对欢迎关于我的代码更惯用的提示!
    • 您的解决方案也将是高性能的,希望这更容易理解意图:)
    猜你喜欢
    • 2016-02-17
    • 1970-01-01
    • 2016-08-15
    • 1970-01-01
    • 2017-08-01
    • 2017-11-13
    • 1970-01-01
    • 1970-01-01
    • 2020-06-01
    相关资源
    最近更新 更多