以以下数据框为例:
df = pd.DataFrame({"val":np.random.rand(8),
"id1":[1,2,3,4,1,2,3,4],
"id2":[1,2,1,2,2,1,2,2],
"id3":[1,1,1,1,2,2,2,2]})
我想用id1相同的id2值替换id3不等于任意引用的id2行
我有一个解决方案,该解决方案可以部分工作,但不能在第二条件下运行(当id3等于参考值时,replcae id2基于与id1相同的值)。如下所述,这会使我的解决方案变得非常鲁棒。
import pandas as pd
import numpy as np
df = pd.DataFrame({"val":np.random.rand(8),
"id1":[1,2,3,4,1,2,3,4],
"id2":[1,2,1,2,2,1,2,2],
"id3":[1,1,1,1,2,2,2,2]})
reference = 1
df.loc[df['id3'] != reference, "id2"] = df[df["id3"]==reference]["id2"].values
print(df)
输出:
val id1 id2 id3
0 0.580965 1 1 1
1 0.941297 2 2 1
2 0.001142 3 1 1
3 0.479363 4 2 1
4 0.732861 1 1 2
5 0.650075 2 2 2
6 0.776919 3 1 2
7 0.377657 4 2 2
此解决方案确实有效,但是仅在id3具有两个不同值的条件下。如果有三个id3值,即
df = pd.DataFrame({"val":np.random.rand(12),
"id1":[1,2,3,4,1,2,3,4,1,2,3,4],
"id2":[1,2,1,2,2,1,2,2,1,1,2,2],
"id3":[1,1,1,1,2,2,2,2,3,3,3,3]})
期望/期望的输出:
val id1 id2 id3
0 0.800934 1 1 1
1 0.505645 2 2 1
2 0.268300 3 1 1
3 0.295300 4 2 1
4 0.564372 1 1 2
5 0.154572 2 2 2
6 0.591691 3 1 2
7 0.896055 4 2 2
8 0.275267 1 1 3
9 0.840533 2 2 3
10 0.192257 3 1 3
11 0.543342 4 2 3
然后很遗憾,我的解决方案停止了工作。如果有人能提供一些技巧来解决这个问题,我将不胜感激。
答案 0 :(得分:2)
如果id1
列类似于组的计数器,则通过过滤Series
并按DataFrame.set_index
首先按reference
组创建助手reference = 1
s = df[df['id3'] == reference].set_index('id1')['id2']
df['id2'] = df['id1'].map(s)
print (df)
val id1 id2 id3
0 0.986277 1 1 1
1 0.873392 2 2 1
2 0.509746 3 1 1
3 0.271836 4 2 1
4 0.336919 1 1 2
5 0.216954 2 2 2
6 0.276477 3 1 2
7 0.343316 4 2 2
8 0.862159 1 1 3
9 0.156700 2 2 3
10 0.140887 3 1 3
11 0.757080 4 2 3
,然后使用Series.map
:
reference = 1
df['g'] = df.groupby('id3').cumcount()
s = df[df['id3'] == reference].set_index('g')['id2']
df['id2'] = df['g'].map(s)
print (df)
val id1 id2 id3 g
0 0.986277 1 1 1 0
1 0.873392 2 2 1 1
2 0.509746 3 1 1 2
3 0.271836 4 2 1 3
4 0.336919 1 1 2 0
5 0.216954 2 2 2 1
6 0.276477 3 1 2 2
7 0.343316 4 2 2 3
8 0.862159 1 1 3 0
9 0.156700 2 2 3 1
10 0.140887 3 1 3 2
11 0.757080 4 2 3 3
如果没有计数器列,请通过GroupBy.cumcount
创建一个新列:
class RefreshableLiveData<T>(
private val source: () -> LiveData<T>
) : MediatorLiveData<T>() {
private var liveData = source()
init {
this.addSource(liveData, ::observer)
}
private fun observer(data: T) {
value = data
}
fun refresh() {
this.removeSource(liveData)
liveData = source()
this.addSource(liveData, ::observer)
}
}