如何基于熊猫数据框中的复杂组合创建指标

时间:2019-11-26 18:58:58

标签: python pandas

我有一个这样的表,其中包含成千上万的clm_id:这里给出了两个clm_id。 clm-id和tmstp的顺序不限。在这里,我以升序显示了tmstp进行解释。如果cd1为50/600且cd2!= 0,则我必须创建一个指标1,否则每个clm_id的指标为0。但是对于同一个clm_id,如果cd1多次出现,那么我必须在tmstp上查看哪个是最新的,以及它们的组合是什么。就像对于clm_id = 1 cd1 = 50&cd2 = 10设置指标= 1一样。在第二行中cd1 = 600&cd2 = 10向下也设置了指标= 1,但在第三行cd1 = 600&cd2 = 0设置了指标=0。但是第一条件cd1 = 50&cd2 = 10仍然具有指标= 1,因此该clm_id指示器= 1仍然有效。但是对于clm_id = 2,由于先前的cd1 = 50和cd2 = 10设置了指示符1,但后来的cd2 = 0,所以指示符= 0,因此指示符变为0。这很复杂,因此需要您的帮助。

clm_id  cd1  cd2  tmstp
1       50 . 10   2019-01-01
1 .     600 .10 . 2010-01-01
1 .     600 .0    2010-01-02
2 .     50   10   2010-01-01
2 .     50 . 0 .  2010-01-02
2 .     42 . 40 . 2010-01-02

最终结果中,每个clm_id的指示器应显示如下:

clm_id indicator
1 .     1
2 .     0

最初,我不知道对于相同的clm_id cd1和cd2组合会随时间(tmstp)改变,因此我尝试过设置指示器:

def add_inj_id(x):
    if (x['cd1'] == 50 or x['cd1'] == 600) and x['cd2'] != '0':
        val = 1
    else:
        val = 0
    return val

inj_df['inj_id'] = inj_df.apply(add_inj_id, axis=1)

1 个答案:

答案 0 :(得分:0)

如果需要,将转换 'tmstp'转换为DateTime,以便进行比较:

df['tmstp'] = pd.to_datetime(df['tmstp'])

'clm_id'将数据框分组:

gb = df.groupby('clm_id')

保留结果的namedtuple列表

import collections
results = []
Result = collections.namedtuple('Result',['clm_id','indicator'])

遍历'clm_id'组;对于每个clm_id除以'cd1';查找最近的cd1并确定其cd2是否不为零;检查50600子组是否为True;存储结果。

for clm_id,group in gb:
    cd1_grp = group.groupby('cd1')
    # Start with the indicators set to False
    ind = {50:False,600:False}
    for cd1,subgroup in cd1_grp:
        if cd1 not in (50,600):
            continue
        most_recent = subgroup.loc[subgroup['tmstp'].idxmax()]
        ind[cd1] = most_recent.cd2 != 0
    indicator = (ind[50] or ind[600]) * 1
    results.append(Result(clm_id,indicator))

>>> results
[Result(clm_id=1, indicator=1), Result(clm_id=2, indicator=0)]

>>> pd.DataFrame(results)
   clm_id  indicator
0       1          1
1       2          0
>>> 

我使用嵌套的for循环(双重groupby)来计算逻辑。这是一个更好的版本-分为两列。

gb1 = df.groupby(['clm_id','cd1'])
d = {}
for (clm_id,cd1),group in gb1:
    if clm_id not in d:
        d[clm_id]=0
    if cd1 not in (50,600):
        continue
    most_recent = group.loc[group['tmstp'].idxmax()]
    d[clm_id] = d[clm_id] or int(most_recent.cd2 != 0)

>>> d
{1: 1, 2: 0}
>>> pd.DataFrame(list(d.items()),columns=['clm_id','indicator'])
   clm_id  indicator
0       1          1
1       2          0
>>> 

可以用d = dict.fromkeys(df['clm_id'].unique(),0)来创建字典。这将使if clm_id not in d:...条件语句变得不必要。尚不清楚这将如何影响性能。


测试DataFrame

import io
s = '''clm_id  cd1  cd2  tmstp
1       50  10   2019-01-01
1      600 10  2010-01-01
1      600 0    2010-01-02
2      50   10   2010-01-01
2      50  0   2010-01-02
2      42  40  2010-01-02'''

df = pd.read_csv(io.StringIO(s), delimiter='\s+')