Pandas根据多个标准将行链接到行

时间:2016-05-15 01:27:10

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

在我看来,这是熊猫的终极挑战,虽然对于你们中的一些人来说可能是最基本的......

我正在尝试将特定工作职位与其对应的调查项目相关联。例如,站点A的主席将归因于来自站点A的受访者提供反馈的调查项目的结果(即“您在何种程度上同意以下声明?:”我认为站点A的质量是足够的整体 “”)。

每个站点有5个站点(0到4)。每个作业位置被分配给一个或多个站点处的一个或多个站点。

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

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

某些调查项目涉及一个或多个站点内的某些站点。

例如,“Positions”表格如下所示:

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. 逗号分隔的响应实际上是从列中压缩的(每个站点和项目一列)。我只提到这一点,因为如果最好不凝结它们,可以做到(或不做)。

  3. 所以这就是我的需要:

    这(我认为):

        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]'
    

    ......所以我还在和它搏斗。

1 个答案:

答案 0 :(得分:1)

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

因此,对于i中的每一行索引pos(我们迭代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的{​​{1}}行。

我们迭代所有位置(即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