在我看来,这是熊猫的终极挑战,虽然对于你们中的一些人来说可能是最基本的......
我正在尝试将特定工作职位与其对应的调查项目相关联。例如,站点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和0,原因并不重要。
逗号分隔的响应实际上是从列中压缩的(每个站点和项目一列)。我只提到这一点,因为如果最好不凝结它们,可以做到(或不做)。
所以这就是我的需要:
这(我认为):
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]'
......所以我还在和它搏斗。
答案 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]]
将只返回df
为position_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
。