【问题标题】:Using Datetimeindex to select rows使用 Datetimeindex 选择行
【发布时间】:2014-04-24 21:55:34
【问题描述】:

我正在使用 Pandas Python 库来比较两个数据帧,每个数据帧由一列日期和两列值组成。其中一个数据框,称为LongDF,包含比另一个更多的日期,称为ShortDF。两个数据框都使用pandas.tseries.index.DatetimeIndex按日期编入索引,见下文(为了演示,我将两者都缩短了)。

LongDF

╔════════════╦════════╦════════╗
║ Date       ║ Value1 ║ Value2 ║
╠════════════╬════════╬════════╣
║ 1990-03-17 ║ 6.84   ║ 1.77   ║
║ 1990-03-18 ║ 0.99   ║ 7.00   ║
║ 1990-03-19 ║ 4.90   ║ 8.48   ║
║ 1990-03-20 ║ 2.57   ║ 2.41   ║
║ 1990-03-21 ║ 4.10   ║ 8.33   ║
║ 1990-03-22 ║ 8.86   ║ 1.31   ║
║ 1990-03-23 ║ 6.01   ║ 6.22   ║
║ 1990-03-24 ║ 0.74   ║ 1.69   ║
║ 1990-03-25 ║ 5.56   ║ 7.30   ║
║ 1990-03-26 ║ 8.05   ║ 1.67   ║
║ 1990-03-27 ║ 8.87   ║ 8.22   ║
║ 1990-03-28 ║ 9.00   ║ 6.83   ║
║ 1990-03-29 ║ 1.34   ║ 6.00   ║
║ 1990-03-30 ║ 1.69   ║ 0.40   ║
║ 1990-03-31 ║ 8.71   ║ 3.26   ║
║ 1990-04-01 ║ 4.05   ║ 4.53   ║
║ 1990-04-02 ║ 9.75   ║ 4.79   ║
║ 1990-04-03 ║ 7.74   ║ 0.44   ║
╚════════════╩════════╩════════╝

ShrotDF

╔════════════╦════════╦════════╗
║ Date       ║ Value1 ║ Value2 ║
╠════════════╬════════╬════════╣
║ 1990-03-25 ║ 1.98   ║ 3.92   ║
║ 1990-03-26 ║ 3.37   ║ 3.40   ║
║ 1990-03-27 ║ 2.93   ║ 7.93   ║
║ 1990-03-28 ║ 2.35   ║ 5.34   ║
║ 1990-03-29 ║ 1.41   ║ 7.62   ║
║ 1990-03-30 ║ 9.85   ║ 3.17   ║
║ 1990-03-31 ║ 9.95   ║ 0.35   ║
║ 1990-04-01 ║ 4.42   ║ 7.11   ║
║ 1990-04-02 ║ 1.33   ║ 6.47   ║
║ 1990-04-03 ║ 6.63   ║ 1.78   ║
╚════════════╩════════╩════════╝

我想做的是参考每个数据集中同一天发生的数据,将两个集合中的数据放入一个公式中,如果更大比某个数字,将日期和值粘贴到另一个数据框中。

我假设我应该使用类似for row in ShortDF.iterrows(): 的东西来遍历ShortDF 上的每个日期,但我不知道如何使用DatetimeIndex 来选择LongDF 上的相应行。

任何帮助将不胜感激

【问题讨论】:

  • 您是仅在同一个 df 中比较每个 df 中的每一行,还是在两个 df 中比较相同日期?如果是这样,您是否只查看两者中都存在的日期?
  • @EdChum 感谢您的回复,我可能应该在上面说得更清楚一点。我在 dfs 之间进行比较。在这种情况下,我碰巧知道 ShortDF 中的所有日期都存在于 LongDF 中,但总的来说,我只对查看两个集合中都存在的日期感兴趣。
  • 在这种情况下合并它们,然后根据您的函数的复杂性使用 lambda 或定义您的函数并按行应用它,所以 merged = df.merge(df1, on='Date') 然后 merged.apply(myfunc, axis=1)merged.apply(lambda row: myfunc(row), axis=1) 我在决定最好的方法之前,需要先看看你的功能,而且这里已经很晚了,所以我可能不会回答
  • 实际上我要做的是合并,然后对合并的 df 执行布尔屏蔽:merged[merged[['Value1','Value2']].max(axis=1) > my_val] 这将返回高于阈值的每一行的最高值。执行合并时,您可能会得到重复的列,其中两个 dfs 中的 Value1 不匹配,默认情况下它们将具有后缀 _x_y,您可以重命名或不关心看到,因为您只想要最高值
  • @EdChum 感谢您的回复。我试了一下,得到了一大串错误。让我看看我是否理解正确:我想在使用任何函数之前合并两个数据帧,对吗?我会使用merged=ShortDF.merge(LongDF, on='Date') 来做到这一点。我理解正确吗?

标签: python pandas indexing dataframe


【解决方案1】:

好的,我现在醒了,使用您的数据您可以做到这一点:

In [425]:
# key here is to tell the merge to use both sides indices
merged = df1.merge(df2,left_index=True, right_index=True)
# the resultant merged dataframe will have duplicate columns, this is fine
merged
Out[425]:
            Value1_x  Value2_x  Value1_y  Value2_y
Date                                              
1990-03-25      5.56      7.30      1.98      3.92
1990-03-26      8.05      1.67      3.37      3.40
1990-03-27      8.87      8.22      2.93      7.93
1990-03-28      9.00      6.83      2.35      5.34
1990-03-29      1.34      6.00      1.41      7.62
1990-03-30      1.69      0.40      9.85      3.17
1990-03-31      8.71      3.26      9.95      0.35
1990-04-01      4.05      4.53      4.42      7.11
1990-04-02      9.75      4.79      1.33      6.47
1990-04-03      7.74      0.44      6.63      1.78

[10 rows x 4 columns]
In [432]:
# now using boolean indexing we want just the rows where there are values larger than 9 and then select the highest value
merged[merged.max(axis=1) > 9].max(axis=1)
Out[432]:
Date
1990-03-30    9.85
1990-03-31    9.95
1990-04-02    9.75
dtype: float64

【讨论】:

    【解决方案2】:

    好的,所以有时我喜欢将 pandas DataFrames 视为字典。这是因为使用字典非常容易,并且将它们视为简单的字典通常意味着您可以找到问题的解决方案,而无需深入研究 pandas。

    因此,在您的示例中,如果 DataFrame 的值通过了一些值测试,我将创建一个常见日期列表,然后使用这些日期创建一个新数据框以访问现有数据框中的值。在我的示例中,测试是 DF1 中的值 1 + DF2 中的值 2 是否大于 10:

    import pandas as pd
    import random 
    random.seed(123)
    
    #Create some data
    DF1 = pd.DataFrame({'Date'      :   ['1990-03-17', '1990-03-18', '1990-03-19', 
                                         '1990-03-20', '1990-03-21', '1990-03-22', 
                                         '1990-03-23', '1990-03-24', '1990-03-25', 
                                         '1990-03-26', '1990-03-27', '1990-03-28',
                                         '1990-03-29', '1990-03-30', '1990-03-31', 
                                         '1990-04-01', '1990-04-02', '1990-04-03'],
                        'Value1'    :   [round(random.uniform(1, 10), 2) 
                                         for x in xrange(18)],
                        'Value2'    :   [round(random.uniform(1, 10), 2) 
                                         for x in xrange(18)]
                       })
    
    DF2 = pd.DataFrame({'Date'      :   ['1990-03-25', '1990-03-26', '1990-03-27', 
                                         '1990-03-28', '1990-03-29', '1990-03-30', 
                                         '1990-03-31', '1990-04-01', '1990-04-02',  
                                         '1990-04-03'],
                        'Value1'    :   [round(random.uniform(1, 10), 2) 
                                         for x in xrange(10)],
                        'Value2'    :   [round(random.uniform(1, 10), 2) 
                                         for x in xrange(10)]
                       })
    
    DF1.set_index('Date', inplace = True)
    DF2.set_index('Date', inplace = True)
    
    #Create a list of common dates, where the values of DF1.Value1  summed 
    #with DF.Value2 is greater than 10
    Common_Set = list(DF1.index.intersection(DF2.index))
    Common_Dates =  [date for date in Common_Set if 
                 DF1.Value1[date] + DF2.Value1[date] > 10]
    
    #And now create the data frame I think you want using the Common_Dates
    
    DF_Output = pd.DataFrame({'L_Value1' : [DF1.Value1[date] for date in Common_Dates],
                              'L_Value2' : [DF1.Value2[date] for date in Common_Dates],
                              'S_Value1' : [DF2.Value1[date] for date in Common_Dates],
                              'S_Value2' : [DF2.Value2[date] for date in Common_Dates]
                             }, index = Common_Dates)
    

    正如评论所暗示的,这在熊猫中绝对是可行的,但对我来说这是一个简单的解决方案。 Common_Dates 操作可以很容易地在一行中完成,但为了清楚起见我没有这样做。

    当然,如果您在两个数据框中都有很多列,那么写出 DF_Output DataFrame 构造函数可能会非常痛苦。如果是这种情况,那么您可以这样做:

    DF1_Out = {'L' + col : [DF1[col][date] for date in Common_Dates] 
                for col in DF1.columns}
    DF2_Out = {'S' + col : [DF2[col][date] for date in Common_Dates] 
                for col in DF2.columns}
    
    DF_Out = {}
    DF_Out.update(DF1_Out)
    DF_Out.update(DF2_Out)
    
    DF_Output2 = pd.DataFrame(DF_Out, index = Common_Dates)
    

    这两种方法都给了我这个:

                LValue1  LValue2  SValue1  SValue2
    1990-03-25     8.67     6.16     3.84     4.37
    1990-03-27     4.03     8.54     7.92     7.79
    1990-03-29     3.21     4.09     7.16     8.38
    1990-03-31     4.93     2.86     7.00     6.92
    1990-04-01     1.79     6.48     9.01     2.53
    1990-04-02     6.38     5.74     5.38     4.03
    

    我想这不会让很多人满意,但这是我解决它的方式。 p.s.如果你能做腿部工作那就太好了:在后续问题中创建数据框。

    【讨论】:

      猜你喜欢
      • 2018-08-18
      • 2019-07-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-17
      • 1970-01-01
      相关资源
      最近更新 更多