Pandas: 新的列值基于匹配的多级列的条件
Pandas: New column value based on the matching multi-level column's conditions
我有以下包含多级列的数据框
In [1]: data = {('A', '10'):[1,3,0,1],
('A', '20'):[3,2,0,0],
('A', '30'):[0,0,3,0],
('B', '10'):[3,0,0,0],
('B', '20'):[0,5,0,0],
('B', '30'):[0,0,1,0],
('C', '10'):[0,0,0,2],
('C', '20'):[1,0,0,0],
('C', '30'):[0,0,0,0]
}
df = pd.DataFrame(data)
df
Out[1]:
A B C
10 20 30 10 20 30 10 20 30
0 1 3 0 3 0 0 0 1 0
1 3 2 0 0 5 0 0 0 0
2 0 0 3 0 0 1 0 0 0
3 1 0 0 0 0 0 2 0 0
在新列中 results
我想 return 包含每个子集(即第二级列)的最大值的组合列名称
我想要的输出应该如下所示
Out[2]:
A B C
10 20 30 10 20 30 10 20 30 results
0 1 3 0 3 0 0 0 1 0 A20&B10&C20
1 3 2 0 0 5 0 0 0 0 A10&B20
2 0 0 3 0 0 1 0 0 0 A30&B30
3 1 0 0 0 0 0 2 0 0 A10&C10
比如第一行:
对于第 'A' 列,最大值在第 '20' 列下 &
对于 'B' 列,'10' 下只有 1 个值 &
对于 'C' 列,它也只是 '20' 下的一个值 &
所以结果将是 A20&B10&C20
编辑:将results
栏中的“+”替换为“&”,显然我被误解了,你们认为我需要求和而我需要用分隔符分隔的列名
编辑2:
由于某些原因,下面@A.B 提供的解决方案对我不起作用。尽管它在他这边工作,并且针对 google colab.
上的示例数据
不知何故 .idxmax(skipna = True)
导致 ValueError: No axis named 1 for object type Series
我找到了一个解决方法,即在此步骤之前转置数据,然后再将其转置回去。
map_res = lambda x: ",".join(list(filter(None,['' if isinstance(x[a], float) else (x[a][0]+x[a][1]) for a in x.keys()])))
df['results'] = df.replace(0, np.nan)\
.T\ # Transpose here
.groupby(level=0)\ # Remove (axis=1) from here
.idxmax(skipna = True)\
.T\ # Transpose back here
.apply(map_res,axis=1)
我仍然想知道为什么没有转置它就不能工作?
尝试:
df["results"] = df.groupby(level=0, axis=1).max().sum(1)
print(df)
打印:
A B C results
10 20 30 10 20 30 10 20 30
0 1 3 0 3 0 0 0 1 0 7
1 3 2 0 0 5 0 0 0 0 8
2 0 0 3 0 0 1 0 0 0 4
3 1 0 0 0 0 0 2 0 0 3
按级别 0 和轴=1 分组
您使用 idxmax 将最大子级索引作为元组获取(同时跳过 NaN)。
将函数应用于行 (axix-1) 以连接名称
在函数(应用于行)中,迭代 keys/columns 并连接列级别。将 Nan(类型为 'float')替换为空字符串并稍后过滤它们。
如果您最初有 NaN 并让它们保留,则不需要 df.replace(0, np.nan)。
map_res = lambda x: ",".join(list(filter(None,['' if isinstance(x[a], float) else (x[a][0]+x[a][1]) for a in x.keys()])))
df['results'] = df.replace(0, np.nan)\
.groupby(level=0, axis=1)\
.idxmax(skipna = True)\
.apply(map_res,axis=1)
这是输出
A B C results
10 20 30 10 20 30 10 20 30
0 1 3 0 3 0 0 0 1 0 A20,B10,C20
1 3 2 0 0 5 0 0 0 0 A10,B20
2 0 0 3 0 0 1 0 0 0 A30,B30
3 1 0 0 0 0 0 2 0 0 A10,C10
想法是将 0
替换为 NaN
,因此如果使用 DataFrame.stack
all rows with NaN
s are removed. Then get indices by DataFrameGroupBy.idxmax
,则将第二个和第三个元组值映射为 map
并将 join
聚合到新的每个索引的列 - 第一级:
df['results'] = (df.replace(0, np.nan)
.stack([0,1])
.groupby(level=[0,1])
.idxmax()
.map(lambda x: f'{x[1]}{x[2]}')
.groupby(level=0)
.agg('&'.join))
print (df)
A B C results
10 20 30 10 20 30 10 20 30
0 1 3 0 3 0 0 0 1 0 A20&B10&C20
1 3 2 0 0 5 0 0 0 0 A10&B20
2 0 0 3 0 0 1 0 0 0 A30&B30
3 1 0 0 0 0 0 2 0 0 A10&C10
我有以下包含多级列的数据框
In [1]: data = {('A', '10'):[1,3,0,1],
('A', '20'):[3,2,0,0],
('A', '30'):[0,0,3,0],
('B', '10'):[3,0,0,0],
('B', '20'):[0,5,0,0],
('B', '30'):[0,0,1,0],
('C', '10'):[0,0,0,2],
('C', '20'):[1,0,0,0],
('C', '30'):[0,0,0,0]
}
df = pd.DataFrame(data)
df
Out[1]:
A B C
10 20 30 10 20 30 10 20 30
0 1 3 0 3 0 0 0 1 0
1 3 2 0 0 5 0 0 0 0
2 0 0 3 0 0 1 0 0 0
3 1 0 0 0 0 0 2 0 0
在新列中 results
我想 return 包含每个子集(即第二级列)的最大值的组合列名称
我想要的输出应该如下所示
Out[2]:
A B C
10 20 30 10 20 30 10 20 30 results
0 1 3 0 3 0 0 0 1 0 A20&B10&C20
1 3 2 0 0 5 0 0 0 0 A10&B20
2 0 0 3 0 0 1 0 0 0 A30&B30
3 1 0 0 0 0 0 2 0 0 A10&C10
比如第一行:
对于第 'A' 列,最大值在第 '20' 列下 &
对于 'B' 列,'10' 下只有 1 个值 &
对于 'C' 列,它也只是 '20' 下的一个值 &
所以结果将是 A20&B10&C20
编辑:将results
栏中的“+”替换为“&”,显然我被误解了,你们认为我需要求和而我需要用分隔符分隔的列名
编辑2: 由于某些原因,下面@A.B 提供的解决方案对我不起作用。尽管它在他这边工作,并且针对 google colab.
上的示例数据不知何故 .idxmax(skipna = True)
导致 ValueError: No axis named 1 for object type Series
我找到了一个解决方法,即在此步骤之前转置数据,然后再将其转置回去。
map_res = lambda x: ",".join(list(filter(None,['' if isinstance(x[a], float) else (x[a][0]+x[a][1]) for a in x.keys()])))
df['results'] = df.replace(0, np.nan)\
.T\ # Transpose here
.groupby(level=0)\ # Remove (axis=1) from here
.idxmax(skipna = True)\
.T\ # Transpose back here
.apply(map_res,axis=1)
我仍然想知道为什么没有转置它就不能工作?
尝试:
df["results"] = df.groupby(level=0, axis=1).max().sum(1)
print(df)
打印:
A B C results
10 20 30 10 20 30 10 20 30
0 1 3 0 3 0 0 0 1 0 7
1 3 2 0 0 5 0 0 0 0 8
2 0 0 3 0 0 1 0 0 0 4
3 1 0 0 0 0 0 2 0 0 3
按级别 0 和轴=1 分组
您使用 idxmax 将最大子级索引作为元组获取(同时跳过 NaN)。
将函数应用于行 (axix-1) 以连接名称
在函数(应用于行)中,迭代 keys/columns 并连接列级别。将 Nan(类型为 'float')替换为空字符串并稍后过滤它们。
如果您最初有 NaN 并让它们保留,则不需要 df.replace(0, np.nan)。
map_res = lambda x: ",".join(list(filter(None,['' if isinstance(x[a], float) else (x[a][0]+x[a][1]) for a in x.keys()])))
df['results'] = df.replace(0, np.nan)\
.groupby(level=0, axis=1)\
.idxmax(skipna = True)\
.apply(map_res,axis=1)
这是输出
A B C results
10 20 30 10 20 30 10 20 30
0 1 3 0 3 0 0 0 1 0 A20,B10,C20
1 3 2 0 0 5 0 0 0 0 A10,B20
2 0 0 3 0 0 1 0 0 0 A30,B30
3 1 0 0 0 0 0 2 0 0 A10,C10
想法是将 0
替换为 NaN
,因此如果使用 DataFrame.stack
all rows with NaN
s are removed. Then get indices by DataFrameGroupBy.idxmax
,则将第二个和第三个元组值映射为 map
并将 join
聚合到新的每个索引的列 - 第一级:
df['results'] = (df.replace(0, np.nan)
.stack([0,1])
.groupby(level=[0,1])
.idxmax()
.map(lambda x: f'{x[1]}{x[2]}')
.groupby(level=0)
.agg('&'.join))
print (df)
A B C results
10 20 30 10 20 30 10 20 30
0 1 3 0 3 0 0 0 1 0 A20&B10&C20
1 3 2 0 0 5 0 0 0 0 A10&B20
2 0 0 3 0 0 1 0 0 0 A30&B30
3 1 0 0 0 0 0 2 0 0 A10&C10