我尽我所能地四处寻找解决方案。我能找到的最接近的是this,但它并不是我想要的。
我试图模拟一个值与其父值之间的关系。特别是试图计算比率。我还想跟踪血统的水平,比如这个项目有多少孩子?
例如,我想输入一个如下所示的pandas df:
id parent_id score
1 0 50
2 1 40
3 1 30
4 2 20
5 4 10
得到这个:
id parent_id score parent_child_ratio level
1 0 50 NA 1
2 1 40 1.25 2
3 1 30 1.67 2
4 2 20 2 3
5 4 10 2 4
因此,对于每一行,我们都会找到其父级的分数,然后计算(parent_score / child_score)并将其作为新列的值。然后某种计数解决方案增加了孩子的水平。
这一直困扰我一段时间,任何帮助都表示赞赏!!!
答案 0 :(得分:3)
第一部分只是合并:
with_parent = pd.merge(df, df, left_on='parent_id', right_on='id', how='left')
with_parent['child_parent_ratio'] = with_parent.score_y / with_parent.score_x
with_parent = with_parent.rename(columns={'id_x': 'id', 'parent_id_x': 'parent_id', 'score_x': 'score'})[['id', 'parent_id', 'score', 'child_parent_ratio']]
>>> with_parent
id parent_id score child_parent_ratio
0 1 0 50 NaN
1 2 1 40 1.250000
2 3 1 30 1.666667
3 4 2 20 2.000000
4 5 4 10 2.000000
对于第二部分,您可以运行breadth-first search。这会创建一个森林,级别是与根的距离,如:
,例如,使用networkx
:
import networkx as nx
G = nx.DiGraph()
G.add_nodes_from(set(with_parent['id'].unique()).union(set(with_parent.parent_id.unique())))
G.add_edges_from([(int(r[1]['parent_id']), int(r[1]['id'])) for r in with_parent.iterrows()])
with_parent['level'] = with_parent['id'].map(nx.shortest_path_length(G, 0))
>>> with_parent
id parent_id score child_parent_ratio level
0 1 0 50 NaN 1
1 2 1 40 1.250000 2
2 3 1 30 1.666667 2
3 4 2 20 2.000000 3
4 5 4 10 2.000000 4
答案 1 :(得分:0)
使用rank
功能
df = df.merge(df.drop('parent_id', axis=1).rename(index=str, columns={'id' :'parent_id', 'score':'score_p'}), on='parent_id', how='left')
df['Ratio'] = df['score_p']/df['score']
df = df.sort_values(by=['id', 'parent_id'])
df['level'] = df.parent_id.rank(method='dense').astype(int)
答案 2 :(得分:0)
这是使用pandas apply方法的可能解决方案:
def parent_child_ratio(row):
if row['parent_id'] != 0:
return df.loc[row['parent_id']]['score'] / row['score']
df['parent_child_ratio'] = df.apply(parent_child_ratio, axis=1)
1 0 50 NaN
2 1 40 1.250000
3 1 30 1.666667
4 2 20 2.000000
5 4 10 2.000000
对于关卡列,不应该只是parent_id + 1
吗?