【问题标题】:Merging dataframes where the common column has repeating values合并公共列具有重复值的数据框
【发布时间】:2023-01-12 18:00:46
【问题描述】:

我想合并几个传感器文件,它们有一个公共列作为“日期”,其值是传感器数据登录的时间。这些传感器每秒记录一次数据。我的任务是将这些传感器数据合并到一个大数据框中。由于传感器数据登录的确切时间之间可能存在毫秒差异,因此我们使用 pandas pd.DatetimeIndex.floor 方法创建了一个 30 秒的窗口。现在我想使用“日期”列合并这些文件。以下是我正在处理的示例:

import pandas as pd


data1 = { 
    'date': ['A', 'A', 'A', 'A', 'B', 'B', 'B', 'B', 'B', 'B', 'C', 'C', 'C', 'C', 'C', 'C', 'D', 'D', 'D'],
    'value1': list(range(1, 20))
}

data2 = { 
    'date': ['A',  'A', 'A', 'B', 'B', 'B', 'B', 'B', 'B', 'C', 'C', 'C', 'C', 'C', 'C', 'D', 'D', 'D', 'D', 'D'],
    'value2': list(range(1, 21))
}

不同的传感器文件不一定具有相同的数据量。传感器数据如下所示。垂直轴可能与时间有关(向下增加)。第二个 (B) 和倒数第二个窗口 (C) 应该重叠,因为它们属于同一时间窗口。

结果数据框应该看起来像这样:

A、B、C 和 D 值表示 30 秒窗口(例如,“A”可以是 07:00:00,“B”可以是 07:00:30,“C”可以是 07:01:00 , D 可以是 07:01:30)。现在我们可以看到,开始和结束窗口可能小于 30(因为传感器每秒记录数据,每个窗口应该有 30 个值。在示例中,B 和 C 窗口的行数应该分别为 30,而不是 6如示例所示)。原因是如果传感器在 07:00:27 开始报告值,则它落在“A”窗口中但只能报告 3 个值。同样,如果传感器在 07:01:04 停止报告值,则它落在 C 的窗口中,但只能报告 4 个值。但是,B 和 C 窗口将始终有 30 个值(在示例中,为了便于理解,我只显示了 6 个)。 我想合并数据帧,以便来自同一窗口的值重叠,如图(B 和 C)所示,而开始和结束窗口应该在没有数据的地方显示 NaN 值。 (在上面的示例中,传感器 1 的值 1 提前 1 秒开始报告数据,而传感器 2 的值 2 在传感器 1 停止报告后 2 秒停止报告数据)。

如何在熊猫中实现这种加入?

【问题讨论】:

    标签: python pandas dataframe data-analysis eda


    【解决方案1】:
    from collections import defaultdict
    import pandas as pd
    
    data1 = {
        'date': ['A', 'A', 'A', 'A', 'B', 'B', 'B', 'B', 'B', 'B', 'C', 'C', 'C', 'C', 'C', 'C', 'D', 'D', 'D'],
        'value1': list(range(1, 20))
    }
    
    data2 = {
        'date': ['A',  'A', 'A', 'B', 'B', 'B', 'B', 'B', 'B', 'C', 'C', 'C', 'C', 'C', 'C', 'D', 'D', 'D', 'D', 'D'],
        'value2': list(range(1, 21))
    }
    
    # Part 1
    
    datas = [data1, data2]
    
    ## Compute where to fill dicts with NaNs
        
    dates = sorted(set(data1["date"] + data2["date"]))
    dds = [{} for i in range(2)]
    for d in dates:
        for i in range(2):
            dds[i][d] = [v for k, v in zip(datas[i]["date"], datas[i]["value%i" % (i + 1)]) if k == d]
    
    ## Fill dicts
        
    nan = float("nan")
    for d in dates:
        n1, n2 = map(len, [dd[d] for dd in dds])
        if n1 < n2:
            dds[0][d] += (n2 - n1) * [nan]
        elif n1 > n2:
            dds[1][d] = (n1 - n2) * [nan] + dds[1][d]
    
    # Part 2: Build the filled data columns
    
    data = defaultdict(list)
    for d in dates:
        n = len(dds[0][d])
        data["date"] += d * n
        for i in range(2):
            data["value%i" % (i + 1)] += dds[i][d]
    data = pd.DataFrame(data)
    

    【讨论】:

      【解决方案2】:

      如果我正确理解了这个问题,您可能正在寻找这样的东西:

      data1 = pandas.DataFrame({
          'date': ['A', 'A', 'A', 'A', 'B', 'B', 'B', 'B', 'B', 'B', 'C', 'C', 'C', 'C', 'C', 'C', 'D', 'D', 'D'],
          'value1': list(range(1, 20))
      })
      
      data2 = pandas.DataFrame({
          'date': ['A',  'A', 'A', 'B', 'B', 'B', 'B', 'B', 'B', 'C', 'C', 'C', 'C', 'C', 'C', 'D', 'D', 'D', 'D', 'D'],
          'value2': list(range(1, 21))
      })
      
      b = pandas.concat([data1, data2]).sort_values(by='date', ascending=True)
      

      【讨论】:

      • 谢谢你的回答。抱歉,我可能不是很清楚。我已经编辑了问题。结果数据应如问题所示。
      猜你喜欢
      • 2021-02-18
      • 2019-02-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-05
      • 1970-01-01
      相关资源
      最近更新 更多