Python 按从组外收集值列表
我有一个数据框:Python 按从组外收集值列表,python,pandas,Python,Pandas,我有一个数据框: df ID值 0 1 0.33 1 1 0.91 2 1 0.28 3 2 0.36 4 2 0.50 5 3 0.47 6 3 0.98 7 3 0.34 8 3 0.37 我想按ID分组并创建两个新列: “values_in”是ID的值列列表 “values_out”是其他ID的值列列表 输出如下: ID values_in
df
ID值
0 1 0.33
1 1 0.91
2 1 0.28
3 2 0.36
4 2 0.50
5 3 0.47
6 3 0.98
7 3 0.34
8 3 0.37
我想按ID分组并创建两个新列:
ID values_in values_out
0 1 [0.33, 0.91, 0.28] [0.36, 0.5, 0.47, 0.98, 0.34, 0.37]
1 2 [0.36, 0.5] [0.33, 0.91, 0.28, 0.47, 0.98, 0.34, 0.37]
2 3 [0.47, 0.98, 0.34, 0.37] [0.33, 0.91, 0.28, 0.36, 0.5]
知道如果我使用经典的groupby
我会自动排除值,我该怎么做
仅供参考:我不关心列表中的顺序。在ID
上使用groupby
,并在列表中为每个分组帧创建相应键为ID
、values\u in
和values\u out
的字典:
d = [{'ID': k,
'values_in': g['Value'].values,
'values_out': df.loc[df['ID'].ne(k), 'Value'].values}
for k, g in df.groupby('ID')]
df_ = pd.DataFrame(d)
结果:
ID values_in values_out
0 1 [0.33, 0.91, 0.28] [0.36, 0.5, 0.47, 0.98, 0.34, 0.37]
1 2 [0.36, 0.5] [0.33, 0.91, 0.28, 0.47, 0.98, 0.34, 0.37]
2 3 [0.47, 0.98, 0.34, 0.37] [0.33, 0.91, 0.28, 0.36, 0.5]
计时(使用包含100个唯一ID
的数据帧进行测试):
使用matmul的单向方式:
new_df = df.groupby("ID")["Value"].apply(list).reset_index(name="values_in")
new_df["values_out"] = new_df["values_in"] @ (1 - np.eye(new_df.shape[0], dtype=int))
print(new_df)
输出:
ID values_in values_out
0 1 [0.33, 0.91, 0.28] [0.36, 0.5, 0.47, 0.98, 0.34, 0.37]
1 2 [0.36, 0.5] [0.33, 0.91, 0.28, 0.47, 0.98, 0.34, 0.37]
2 3 [0.47, 0.98, 0.34, 0.37] [0.33, 0.91, 0.28, 0.36, 0.5]
Id values
0 1 12
1 1 13
2 2 14
3 2 15
4 2 12
5 3 12
我正在使用同一场景的另一个示例来演示如何做到这一点:
ids=[1,1,2,2,2,3]
values=[12,13,14,15,12,12]
df = pd.DataFrame({'Id':ids,'values':values})
df
输出:
ID values_in values_out
0 1 [0.33, 0.91, 0.28] [0.36, 0.5, 0.47, 0.98, 0.34, 0.37]
1 2 [0.36, 0.5] [0.33, 0.91, 0.28, 0.47, 0.98, 0.34, 0.37]
2 3 [0.47, 0.98, 0.34, 0.37] [0.33, 0.91, 0.28, 0.36, 0.5]
Id values
0 1 12
1 1 13
2 2 14
3 2 15
4 2 12
5 3 12
现在,您可以分别获取中的值和中的值
df2 = pd.DataFrame()
for i in df["Id"].unique(): # Iterate through unique values of Ids
in_list = list(df.loc[df['Id']==i, 'values']) # values_in
out_list = list(df.loc[df['Id']!=i, 'values']) #values_out
df2 = df2.append([[i,in_list,out_list]]) #append each records
df2.columns = ["ID","Values_in","Values_out"] #rename columns
输出:
ID Values_in Values_out
0 1 [12, 13] [14, 15, 12, 12]
0 2 [14, 15, 12] [12, 13, 12]
0 3 [12] [12, 13, 14, 15, 12]
如果不需要重复的值,可以使用set而不是list来设置输入值和输出值使用自定义函数,并按ID
中的值进行筛选:
我尝试了所有的解决方案,但都不是很有效(循环太慢)
我的解决方案是交叉连接并删除重复项
df_-in=df.groupby('ID')['Value'])。应用(列表)。重置索引(name=“values_-in”)
df_out=pd.merge(df,df,how=“交叉”)
df_out=df_out.loc[df_[“ID_x”]!=df_[“ID_y”]”。groupby('ID_x')['Value_y']。应用(列表)。重置索引(name=“values_out”)
final_df=pd.merge(df_in,df_out,on=“ID”,how=“full”)
@jezrael这有点像黑客,但我试了一下;)什么是matmul
?@Steven矩阵乘法,可以与运算符@I have a errorTypeError一起使用:当前不支持对象数组
。这是因为我的分组键实际上是一个复合键吗?它出现在哪一行?我仍然在考虑条件df['Value'].isin(g['Value'])
如果重复并且不幸的是您的答案失败了,那么工作正常{'ID':[1,1,1,2,2,3,3,3],'Value':[0.98,0.28,0.36,0.98,0.47,0.98,0.34,0.37]}
@jezrael如果需要考虑重复,那么在这种情况下,只需删除isin
就足够了。@ShubhamSharma感谢您的回答。对于复合密钥,您将如何执行相同的操作<代码>[“ID1”,“ID2”]
而不仅仅是“ID”
?@Steven我想你可以在ID1
和ID2
上使用groupby
,然后使用上面的代码。有些事情可能会奏效。。