数据帧中父节点的总和值

时间:2019-06-15 01:03:12

标签: python-3.x pandas

我有一个df(下面有一小部分)。我正在尝试添加额外的tw0列rolled_doc_cntrolled_doc_cnt_all,其中包含当前行及其所有子行的doc_cnt / doc_cnt_all之和。在下面非常有限的行中,df.at[0,'rolled_doc_cnt'] = 1317df.at[0,'rolled_doc_cnt_all'] = 3540

    SYMBOL  level   not-allocatable additional-only doc_cnt doc_cnt_all parent
0   A   2   True    False   0   0   
1   A01 4   True    False   0   0   A
2   A01B    5   True    False   0   0   A01
3   A01B   1/00 7   False   False   198 244 A01B
4   A01B   1/02 8   False   False   230 538 A01B   1/00
5   A01B   1/022    9   False   False   83  238 A01B   1/02
6   A01B   1/024    9   False   False   28  63  A01B   1/02
7   A01B   1/026    9   False   False   100 120 A01B   1/02
8   A01B   1/028    9   False   False   27  82  A01B   1/02
9   A01B   1/04 9   False   False   29  54  A01B   1/02
10  A01B   1/06 8   False   False   78  508 A01B   1/00
11  A01B   1/065    9   False   False   118 150 A01B   1/06
12  A01B   1/08 9   False   False   71  326 A01B   1/06
13  A01B   1/10 9   False   False   14  30  A01B   1/06
14  A01B   1/12 9   False   False   24  86  A01B   1/06
15  A01B   1/14 9   False   False   44  131 A01B   1/06
16  A01B   1/16 8   False   False   159 518 A01B   1/00
17  A01B   1/165    9   False   False   50  114 A01B   1/16
18  A01B   1/18 9   False   False   64  338 A01B   1/16

我在创建parenthere方面获得了一些帮助。

def GetParent():
    # level      0  1  2  3  4  5  6  7  8  9  10 11  12  13  14  15  16  17  18  19, 20
    hierarchy = [0, 0, 0, 0, 2, 4, 0, 5, 7, 8, 9,
                 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
    parent = ['']*len(hierarchy)

    def func(row):
        # print(row)
        symbol, level = row[['SYMBOL', 'level']]

        parent_level = hierarchy[level]
        parent_symbol = parent[parent_level]

        parent[level] = symbol

        return pd.Series([parent_symbol], index=['parent'])

    return func


# create a column with the parents
st = time()
parents = dfa.apply(GetParent(), axis=1)
dfa = pd.concat([dfa, parents], axis=1)
print((time()-st)/60, 'minutes elapsed')

我尝试在spyder中调试此代码,因此我可以看到在前进df行时列表parent的变化,但是我无法弄清楚如何跳入功能GetParent()跳到熊猫函数apply()中。最终跳入apply()会导致我遇到递归错误。

我试图对GetParents()进行一些修改,以同时跟踪每个级别上每个符号的文档计数,但是后来我意识到我正在跟踪父节点的文档计数,但是不是孩子。因此,使用上述df,我如何能够创建类似以下df的内容?

    SYMBOL  level   not-allocatable additional-only doc_cnt doc_cnt_all parent  rolled_doc_cnt  rolled_doc_cnt_all
0   A   2   TRUE    FALSE   0   0       1317    3540
1   A01 4   TRUE    FALSE   0   0   A   1317    3540
2   A01B    5   TRUE    FALSE   0   0   A01 1317    3540
3   A01B   1/00 7   FALSE   FALSE   198 244 A01B    1317    3540
4   A01B   1/02 8   FALSE   FALSE   230 538 A01B   1/00 497 1095
5   A01B   1/022    9   FALSE   FALSE   83  238 A01B   1/02 83  238
6   A01B   1/024    9   FALSE   FALSE   28  63  A01B   1/02 28  63
7   A01B   1/026    9   FALSE   FALSE   100 120 A01B   1/02 100 120
8   A01B   1/028    9   FALSE   FALSE   27  82  A01B   1/02 27  82
9   A01B   1/04 9   FALSE   FALSE   29  54  A01B   1/02 29  54
10  A01B   1/06 8   FALSE   FALSE   78  508 A01B   1/00 349 1231
11  A01B   1/065    9   FALSE   FALSE   118 150 A01B   1/06 118 150
12  A01B   1/08 9   FALSE   FALSE   71  326 A01B   1/06 71  326
13  A01B   1/10 9   FALSE   FALSE   14  30  A01B   1/06 14  30
14  A01B   1/12 9   FALSE   FALSE   24  86  A01B   1/06 24  86
15  A01B   1/14 9   FALSE   FALSE   44  131 A01B   1/06 44  131
16  A01B   1/16 8   FALSE   FALSE   159 518 A01B   1/00 273 970
17  A01B   1/165    9   FALSE   FALSE   50  114 A01B   1/16 50  114
18  A01B   1/18 9   FALSE   FALSE   64  338 A01B   1/16 64  338
  

也可以随时告诉我,我尝试执行此操作的方法不是最佳方法,并建议另一种方法

1 个答案:

答案 0 :(得分:1)

获取父符号的函数( GetParent )可以简化一些:

def GetParent():
    hierarchy = [0, 0, 0, 0, 2, 4, 0, 5, 7, 8, 9, 10,
                 11, 12, 13, 14, 15, 16, 17, 18, 19]
    parent = ['']*len(hierarchy)
    def func(row):
        symbol, level = row[['SYMBOL', 'level']]
        parent_level = hierarchy[level]
        parent_symbol = parent[parent_level]
        parent[level] = symbol
        return parent_symbol
    return func

即它只返回 parent_symbol (不是 Series ),然后可以 应用于目标列的直接创建

dfa['parent'] = dfa.apply(GetParent(), axis=1)

我在您的示例数据上尝试了此功能,并没有错误

请注意, GetParent 最多可以处理20个层次, 因此,错误的根源可能是您的完整数据具有更多 等级?

在发生此错误的地方以及错误消息是什么,您都没有写任何东西。 从这一点开始寻找错误原因。

另一个提示:从在您的某些初始部分运行此代码开始 数据(例如前半部分)。目的是找到源行, 错误发生。然后在此行非常彻底(有点 之前)。这可能会给您一些有关错误原因的线索。

编辑

我想出了一个无论层次结构深度如何都应起作用的解决方案。

def GetParent():
    par = {0: ''}
    def func(row):
        symbol, level = row[['SYMBOL', 'level']]
        parLevel = level - 2 if level in [2, 4, 7] else level - 1
        parSym = par[parLevel]
        par[level] = symbol
            return parSym
    return func

请注意,“缺少层次结构级别”的问题已在以下内容中解决:

parLevel = level - 2 if level in [2, 4, 7] else level - 1

对于缺少的级别“紧随其后”的级别返回 level-2 level-1 表示所有其他级别。

父符号保存在“内部”字典中,因此没有问题 列表索引超出范围。

像上面一样应用此功能,直接创建目标列。

编辑2

我看到您设法计算了祖先,所以现在如何计算总和 感兴趣的列。

关于熊猫中树结构的操作, 我在第 StackOverflow 页上找到了一段有趣的代码:

Hierarchical data: efficiently build a list of every descendant for each node

从那里复制 list_ancestors 函数和其他2个函数 它使用的是 trace_nodes numpy_col_inner_many_to_one_join

在这里我将不再重复此代码。

然后运行:

links = list_ancestors(dfa[['SYMBOL', 'parent']].values)

list_ancestors 函数生成一个带有后代的数据框 和 ancestor 列,包括祖先和后代之间的“链接” 任何深度(到现在为止,您只有直接个后代)。

要添加 SYMBOL doc_cnt doc_cnt_all 列,请运行:

links2 = pd.merge(links, dfa[['SYMBOL', 'doc_cnt', 'doc_cnt_all']],
    left_on='descendant', right_on='SYMBOL', copy=False)

现在开始求和:

s1 = links2.groupby('ancestor')['doc_cnt', 'doc_cnt_all'].apply(sum)
s2 = dfa[['SYMBOL', 'doc_cnt', 'doc_cnt_all']].set_index('SYMBOL')
s3 = pd.concat([s1, s2]).groupby(level=0).apply(sum)

一些解释:

  • s1 包含所有(两个感兴趣的列)的总和 后裔(任意深度),但没有“自己”的值 这些列。
  • s2 依次仅包含自己的“缺失”值。
  • s3 对这些值求和。

仅剩下的两个步骤是:

  • 将列名称更改为目标名称,
  • dfa s3 加入。

执行此操作的代码是:

s3.columns=['rolled_doc_cnt', 'rolled_doc_cnt_all']
dfa.join(s3, on='SYMBOL')

对于您的测试数据,我只是得到了预期的结果。