熊猫根据多个条件替换行

时间:2020-04-15 09:26:44

标签: python pandas dataframe

以以下数据框为例:

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

然后很遗憾,我的解决方案停止了工作。如果有人能提供一些技巧来解决这个问题,我将不胜感激。

1 个答案:

答案 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)
    }
}