Pandas分组-应用:无法重新索引重复轴

6

我正在对一个DataFrame执行分组操作。在每个组上,我需要重命名两列并删除一列,以便每个组具有以下形式:

index(timestamp) | column-x | column-y
...              |  ....    | ..... 

索引是一个时间戳,每个组都将共享此时间戳。相反,'column-x'和'column-y'对于每个组将是不同的。因此,我的目标是在索引上连接所有组,以便我拥有一个唯一的DataFrame,如下所示:

index(timestamp) | column-x1 | column-y1 | column-x2 | column-y2 | ...
...              |  .....    | ......    |  .......  | .......   | ...

我应用于每个组的功能是(在迭代时可以进行原地编辑吗?):
def process_ssp(df_ssp):
    sensor_name = df_ssp.iloc[0]['subsystem-sensor-parameter'] # to be used as column name
    df_ssp.rename(columns = {
        'value_raw': '%s_raw' % sensor_name,
        'value_hrf': '%s_hrf' % sensor_name,
    }, inplace = True)
    df_ssp.drop('subsystem-sensor-parameter', axis='columns', inplace=True) # since this is the column I am grouping on I guess this isn't the right thing to do?
    return df_ssp

然后我调用:

res = df_node.groupby('subsystem-sensor-parameter', as_index=False).apply(process_ssp)

这会产生错误:

ValueError: cannot reindex from a duplicate axis

编辑: 数据集示例https://drive.google.com/file/d/1RvPE1t3BmjeaqCNkVqGwmokCFQQp77n8/view?usp=sharing


你能提供带有“子系统-传感器-参数”列的源表吗? - Hubert Dudek
是的,我已经在上面的帖子中更新了一个示例。 - user1315621
@shadowtalker,你能解释一下你在代码的哪个部分遇到了问题吗?你实际的问题是否与这个问题、代码或数据有关? - cs95
2个回答

1
您可以先为MultiIndex添加列subsystem-sensor-parameter,然后使用unstack进行重塑,按第二级别对列中的MultiIndex进行排序并更改它们的位置。最后使用mapjoin将MultiIndex扁平化:
res = (df_node.set_index('subsystem-sensor-parameter', append=True)
                          .unstack()
                          .sort_index(axis=1, level=1)
                          .swaplevel(0,1, axis=1)) 
res.columns = res.columns.map('_'.join)

这个函数没有出现错误,但它并没有完全达到我的期望。res变量是一个DataFrame,其索引的类型为:('nc-devices-alphasense',Timestamp('2019-03-05 00:02:40'))。这会创建大量NaN值。相反,我只想在索引值上有时间戳。我该如何实现?通过在process_ssp()中打印df_ssp,我可以看到df_ssp具有所需的格式。然而,res没有像我希望的那样连接组,因为它改变了索引,将子系统-传感器-参数添加到时间戳中。 - user1315621
缺失值是预期的输出,因为在DataFrame中,如果某些组没有匹配,它们将填充NaN,因此只有匹配的组才填充日期,其他不填充。 - jezrael
太好了!最后一条评论就是我想要的。如果你想把它写成答案而不是评论,我会批准它作为正确答案。我会努力理解它是如何工作的 ;) 谢谢! - user1315621

1

我可以通过迭代组而不是使用apply成功应用您的代码并产生您想要的输出:

import pandas as pd
df = pd.read_csv('/Users/jeffmayse/Downloads/sample.csv')
df.set_index('timestamp', inplace=True)

def process_ssp(df_ssp):
    sensor_name = df_ssp.iloc[0]['subsystem-sensor-parameter'] # to be used as column name
    df_ssp.rename(columns = {
        'value_raw': '%s_raw' % sensor_name,
        'value_hrf': '%s_hrf' % sensor_name,
    }, inplace = True)
    df_ssp.drop('subsystem-sensor-parameter', axis='columns', inplace=True) # since this is the column I am grouping on I guess this isn't the right thing to do?
    return df_ssp

groups = df.groupby('subsystem-sensor-parameter')
out = []
for name, group in groups:
    try:
        out.append(process_ssp(group))
    except:
        print(name)
pd.concat(out).shape

Out[7]: (16131, 114)

事实上,问题在于apply方法中,因为你的函数不需要产生错误:

df.groupby('subsystem-sensor-parameter', as_index=False).apply(lambda x: x)

同样会评估为ValueError: cannot reindex from a duplicate axis

然而,这个语句的评估结果与我们预期的一样:

df.reset_index(inplace=True)
df.groupby('subsystem-sensor-parameter', as_index=False).apply(process_ssp)

Out[22]: 
      nc-devices-alphasense_hrf  ... wagman-uptime-uptime_raw
0                             0  ...                      NaN
1                           NaN  ...                      NaN
2                           NaN  ...                      NaN
3                           NaN  ...                      NaN
...

问题在于您拥有具有重复值的 DatetimeIndex.apply 尝试将结果集合并在一起,但不确定如何组合具有重复值的索引。至少我认为是这样。重置索引然后再试一次。
编辑:要扩展,当尝试重新索引 DatetimeIndex 时(即,您拥有一个每小时的索引,并希望将其转换为每秒分辨率的索引,或通常填充缺失的小时),您会经常看到此错误。您使用 reindex,但如果您的索引具有重复值,则会失败。我猜这就是这里发生的事情:被应用函数产生的数据帧具有重复的索引值,错误来自尝试通过在具有重复项的 DatetimeIndex 上调用 reindex 来生成输出。重置索引有效是因为现在您的索引都是唯一的,而且对于此操作,timestamp 列并不重要。

很不幸,我无法通过两个简单的示例重现错误:data = pd.DataFrame({'a': [1,2,3,4,5], 'b': [11,11,11,12,12]}, index=['q','r','r','r','t'])data.index = pd.to_datetime(['2019-03-01', '2019-03-04', '2019-03-04', '2019-03-04', '2019-05-12'])。尝试使用.groupby(level=0)/.groupby('b').apply()中的各种函数,例如删除列,这会导致各种重复索引情况,但似乎没有问题。 - shadowtalker
1
我很想称这为Pandas的一个bug并提交报告。这绝对不是一个有用的错误提示。 - shadowtalker
@shadowtalker,我认为这不是一个bug。你能告诉我们你的代码哪一部分出了问题吗? - anky
@anky_91 忘记我的代码吧。我评论的重点是,我无法使用他们描述的推理重现此答案中描述的问题,因此在那些数据中(或在该特定函数中)显然有其他触发错误的东西。 - shadowtalker
1
我认为你的示例和真实数据中的索引不同。如果你跟随堆栈跟踪,你的数据需要使用pandas._libs.index.IndexEngine.get_indexer_non_unique方法,而你的示例代码则不需要。可以说,你的真实数据具有复杂的索引,这导致了一些问题。我仍在尝试调试找出原因,但要明确的是,问题似乎是仅使用timestamp,因为即使作为str类型,它也会导致相同的错误。 - Jeff
由于赏金即将到期,我会提前将其授予这个答案。如果我这周找到时间,我也会尝试重现这个问题。 - shadowtalker

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接