【问题标题】:Pandas Link Rows to Rows Based on Multiple CriteriaPandas 将行链接到基于多个标准的行
【发布时间】:2016-05-15 01:27:10
【问题描述】:

在我看来,这是 Pandas 的终极挑战,尽管对你们中的一些人来说可能是初级的......

我正在尝试将特定工作职位与其对应的调查项目联系起来。例如,站点 A 的总裁将归因于站点 A 的受访者提供反馈的调查项目的结果(即“您在多大程度上同意以下陈述?:“我认为站点 A 的质量是足够的整体"")。

每个站点有 5 个站点(0 到 4)。每个工作职位被分配到一个或多个站点的一个或多个站点。

例如,一个站点的总裁在该站点内的所有站点工作,而承包商可能只在几个站点工作,可能在 2 个不同的站点。

收集了有关每个站点内每个站点质量的调查数据。

一些调查项目与一个或多个站点内的某些站点有关。

例如,“职位”表如下所示:

import pandas as pd
import numpy as np

pos = pd.DataFrame({'Station(s)':[',1,2,,','0,1,2,3,4'],
                    'Position':['Contractor','President'],
                    'Site(s)':['A,B','A'],
                    'Item(s)':['1','1,2']
                   })

pos[['Position','Site(s)','Station(s)','Item(s)']]

    Position    Site(s)     Station(s)   Item(s)
0   Contractor  A,B          ,1,2,,         1
1   President   A           0,1,2,3,4       1,2

调查数据表如下所示:

sd = pd.DataFrame({'Site(s)':['A','B','B','C','A','A'],
                   'Station(s)':[',1,2,,',',1,2,,',',,,,',',1,2,,','0,1,2,,',',,2,,'],
                   'Item 1':[1,1,0,0,1,np.nan],
                   'Item 2':[1,0,0,1,0,1]})
sd[['Site','Station(s)','Item 1','Item 2']]

    Site    Station(s)  Item 1  Item 2
0      A       ,1,2,,          1    1
1      B       ,1,2,,          1    0
2      B       ,,,,            0    0
3      C       ,1,2,,          0    1
4      A       0,1,2,,         1    0
5      A       ,,2,,           NaN  1

2 旁注:

  1. 由于不重要的原因,项目数据已被编码为 1 和 0。

  2. 逗号分隔的响应实际上是从列中压缩的(每个站点和项目一列)。我只提到这一点是因为如果最好不要压缩它们,那可以(或不)。

这就是我需要的:

这个(我认为):

    Contractor  President Site(s)  Station(s)   Item 1  Item 2
0      1           1        A       ,1,2,,        1       1
1      1           0        B       ,1,2,,        1       0
2      0           0        B       ,,,,          0       0
3      0           0        C       ,1,2,,        0       1
4      0           1        A       0,1,2,,       1       0
5      1           1        A       ,,2,,         NaN     1

逻辑:

承包商在站点 A 和 B 工作,并且只应与在其中一个站点工作的受访者相关联。 在这些受访者中,他应该只与在 1 号或 2 号站工作但没有在 任何其他(即站 0)。

因此,承包商在 df2 中感兴趣的行是索引 0、1 和 5。 总统感兴趣的行来自索引 0、4 和 5。

...最终,这是:

    Position    Overall%
0   Contractor  100
1   President   80

逻辑:

由于总统关心第 1 项和第 2 项,因此需要考虑 5 个数字:第 1 项中的(1 和 1)和第 2 项中的(1、0 和 1)。 项目总和为 4,项目计数为 5(同样,不计算 'NaN'),即为 80%。

由于承包商只关心项目 1,因此需要考虑 2 个数字:1 和 1 - 不应计算“NaN” - (分别来自感兴趣的行)。因此,总和是计数中的 2,即 2,即 100%

提前致谢!

更新

我知道这行得通 (top answer just under question),但如何将其应用于这种情况?我试过这个(只是为了尝试逻辑的第一部分):

for i in pos['Position']:
    sd[i]=[x for x in pos.loc['Site(s)'] if x in sd['Site']]

...但它抛出了这个错误:

KeyError: 'the label [Site(s)] is not in the [index]'

...所以我还在努力。

【问题讨论】:

    标签: python-3.x pandas pivot-table


    【解决方案1】:

    如果我理解正确,您想为pos 中的每个职位添加一列到sd。 (这是第一个任务。)

    因此,对于pos 中的每个行索引i(我们遍历pos 中的行),我们可以创建一个唯一的布尔列:

    # PSEUDOCODE:
    sd[position_name_i] = (sd['Site'] IS_CONTAINED_IN pos.loc[i,'Site(s)']) and (sd['Station(s)'] IS_CONTAINED_IN pos.loc[i,'Station(s)'])
    

    我希望这里的逻辑清晰且符合您的目标。

    表达式X IS_CONTAINED_IN Y 可以以多种不同的方式实现。 (我可以认为 X 和 Y 是集合,然后是 X.subset(Y)。或者就位掩码 X、Y 和 bitwise_xor 而言。)

    列名position_name_i 可能只是一个整数i。 (或者如果此列包含唯一值,则使用更有意义的 pos.loc[i,'Position']。)

    如果完成了,我们可以执行其他任务。现在,df[df[position_name_i]] 将只返回 dfposition_name_i 为 True 的行。

    我们遍历所有位置(即pos 中的行)。对于每个职位:

    # number of non-nan entries in 'Item 1' and 'Item 2' relevant for the position:
    total = df.loc[df['position_name_i'], ['Item 1', 'Item 2']].count().sum()
    # number of 1's among these entries: 
    partial = df.loc[df['position_name_i'], ['Item 1', 'Item 2']].sum().sum()
    

    给定位置的最终Overall%100*partial/total

    【讨论】:

    • 你的逻辑看起来很合理。对于台站,必须同时满足这两个条件: 1. 调查中的至少一个元素 (sd['Station(s)']) 必须存在于位置 (pos['Station(s)'])。 2. 调查中的任何元素 (sd['Station(s)']) 不得在位置 (pos['Station(s)'] 中找到。
    • 对于站点,来自 sd['Site(s)'] 的站点必须存在于来自 pos['Site(s)'] 的站点中。
    • 我不确定我是否理解车站的条件 2。我猜,条件 1 是“X 和 Y 的交点不为空”。无论如何,无论条件如何,它们总是可以用集合论的语言编写(即作为关于集合并集、交集、包含等的逻辑语句)。如果您认为我的答案不太正确,请随时编辑它。如果有不清楚的地方,请询问。
    • 我认为这可能是 TL;DR 类型的帖子。我将发布一些较小的问题,这些问题将导致答案,但与此同时我会留下这个。我会在发布时链接到每个单独的帖子。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-30
    • 2016-08-24
    • 1970-01-01
    • 1970-01-01
    • 2017-12-31
    • 1970-01-01
    相关资源
    最近更新 更多