我有一个df(下面有一小部分)。我正在尝试添加额外的tw0列rolled_doc_cnt
和rolled_doc_cnt_all
,其中包含当前行及其所有子行的doc_cnt
/ doc_cnt_all
之和。在下面非常有限的行中,df.at[0,'rolled_doc_cnt'] = 1317
和df.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
我在创建parent
列here方面获得了一些帮助。
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
也可以随时告诉我,我尝试执行此操作的方法不是最佳方法,并建议另一种方法
答案 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 表示所有其他级别。
父符号保存在“内部”字典中,因此没有问题 列表索引超出范围。
像上面一样应用此功能,直接创建目标列。
我看到您设法计算了祖先,所以现在如何计算总和 感兴趣的列。
关于熊猫中树结构的操作, 我在第 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)
一些解释:
仅剩下的两个步骤是:
执行此操作的代码是:
s3.columns=['rolled_doc_cnt', 'rolled_doc_cnt_all']
dfa.join(s3, on='SYMBOL')
对于您的测试数据,我只是得到了预期的结果。