【问题标题】:Reversing 'one-hot' encoding in Pandas在 Pandas 中反转 \'one-hot\' 编码
【发布时间】:2023-01-16 00:33:31
【问题描述】:

我想从这个基本上是热编码的数据帧开始。

 In [2]: pd.DataFrame({"monkey":[0,1,0],"rabbit":[1,0,0],"fox":[0,0,1]})

    Out[2]:
       fox  monkey  rabbit
    0    0       0       1
    1    0       1       0
    2    1       0       0
    3    0       0       0
    4    0       0       0

对于这个“反向”单热编码的。

    In [3]: pd.DataFrame({"animal":["monkey","rabbit","fox"]})
    Out[3]:
       animal
    0  monkey
    1  rabbit
    2     fox

我想可以巧妙地使用 apply 或 zip 来做事,但我不确定如何......有人可以帮忙吗?

我使用索引等来尝试解决这个问题并没有取得多大成功。

【问题讨论】:

  • @PeadarCoyle,你能为这个输入 DF 发布你想要的 DF:pd.DataFrame({'dog': {0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 1}, 'fox': {0: 0, 1: 0, 2: 1, 3: 0, 4: 0, 5: 0}, 'monkey': {0: 0, 1: 1, 2: 0, 3: 0, 4: 0, 5: 0}, 'rabbit': {0: 1, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0}}),因为现在我不明白你想要的 DF 吗?
  • @PeadarCoyle,能否请您澄清一下您的输入数据集是否在一列中可能有多个1?你是如何获得只包含零的行的?

标签: python pandas dataframe


【解决方案1】:

更新:我认为ayhan是对的,应该是:

df.idxmax(axis=1)

演示:

In [40]: s = pd.Series(['dog', 'cat', 'dog', 'bird', 'fox', 'dog'])

In [41]: s
Out[41]:
0     dog
1     cat
2     dog
3    bird
4     fox
5     dog
dtype: object

In [42]: pd.get_dummies(s)
Out[42]:
   bird  cat  dog  fox
0   0.0  0.0  1.0  0.0
1   0.0  1.0  0.0  0.0
2   0.0  0.0  1.0  0.0
3   1.0  0.0  0.0  0.0
4   0.0  0.0  0.0  1.0
5   0.0  0.0  1.0  0.0

In [43]: pd.get_dummies(s).idxmax(1)
Out[43]:
0     dog
1     cat
2     dog
3    bird
4     fox
5     dog
dtype: object

旧答案:(很可能是错误的答案)

尝试这个:

In [504]: df.idxmax().reset_index().rename(columns={'index':'animal', 0:'idx'})
Out[504]:
   animal  idx
0     fox    2
1  monkey    1
2  rabbit    0

数据:

In [505]: df
Out[505]:
   fox  monkey  rabbit
0    0       0       1
1    0       1       0
2    1       0       0
3    0       0       0
4    0       0       0

【讨论】:

  • 如果任何列重复会发生什么。说两只猴子? [1,3 ] 这会捡起来吗?
  • 不应该是df.idxmax(axis=1)吗?
  • @ayhan,它看起来好多了,但不幸的是,它并不总是能正常工作!
  • @ayhan,试试这个 DF:pd.DataFrame({'dog': {0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 1}, 'fox': {0: 0, 1: 0, 2: 1, 3: 0, 4: 0, 5: 0}, 'monkey': {0: 0, 1: 1, 2: 0, 3: 0, 4: 0, 5: 0}, 'rabbit': {0: 1, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0}})
  • 实际上应该是每行一个 1。你可以试试pd.Series(['dog', 'cat', 'dog', 'bird']).str.get_dummies()。 get_dummies 将始终生成这样的结构(连续不超过一个 1)。 OP的问题是有问题的。他们想要用于创建假人的原始数组,但示例中的顺序是错误的(应该是兔子、猴子、狐狸)。除此之外,就像我说的那样,在创建虚拟对象时删除其中一列是一种常见的做法(以避免多重共线性),但为了返回到原始数组,我们必须知道该列是什么。
【解决方案2】:

我会使用 apply 来解码列:

In [2]: animals = pd.DataFrame({"monkey":[0,1,0,0,0],"rabbit":[1,0,0,0,0],"fox":[0,0,1,0,0]})

In [3]: def get_animal(row):
   ...:     for c in animals.columns:
   ...:         if row[c]==1:
   ...:             return c

In [4]: animals.apply(get_animal, axis=1)
Out[4]: 
0    rabbit
1    monkey
2       fox
3      None
4      None
dtype: object

【讨论】:

    【解决方案3】:

    这适用于单个和多个标签。

    我们可以使用高级索引来解决这个问题。 Here 是链接。

    import pandas as pd
    
    df = pd.DataFrame({"monkey":[1,1,0,1,0],"rabbit":[1,1,1,1,0],
        "fox":[1,0,1,0,0], "cat":[0,0,0,0,1]})
    
    df['tags']='' # to create an empty column
    
    for col_name in df.columns:
        df.ix[df[col_name]==1,'tags']= df['tags']+' '+col_name
    
    print df
    

    结果是:

       cat  fox  monkey  rabbit                tags
    0    0    1       1       1   fox monkey rabbit
    1    0    0       1       1       monkey rabbit
    2    0    1       0       1          fox rabbit
    3    0    0       1       1       monkey rabbit
    4    1    0       0       0                 cat
    

    解释: 我们遍历数据框上的列。

    df.ix[selection criteria, columns to write value] = value
    df.ix[df[col_name]==1,'tags']= df['tags']+' '+col_name
    

    上面的行基本上找到了 df[col_name] == 1 的所有地方,选择列 'tags' 并将其设置为 RHS 值 df['tags']+' '+ col_name

    笔记:.ix 自 Pandas v0.20 以来已被弃用。您应该酌情改用.loc.iloc

    【讨论】:

      【解决方案4】:

      我会做:

      cols = df.columns.to_series().values
      pd.DataFrame(np.repeat(cols[None, :], len(df), 0)[df.astype(bool).values], df.index[df.any(1)])
      


      定时

      MaxU 的方法对大型数据帧有优势

      小号 df 5 x 3

      大号 df 1000000 x 52

      【讨论】:

        【解决方案5】:

        您可以尝试使用melt()。当一行有多个 OHE 标签时,此方法也适用。

        # Your OHE dataframe 
        df = pd.DataFrame({"monkey":[0,1,0],"rabbit":[1,0,0],"fox":[0,0,1]})
        
        mel = df.melt(var_name=['animal'], value_name='value') # Melting
        
        mel[mel.value == 1].reset_index(drop=True) # this gives you the result 
        

        【讨论】:

          【解决方案6】:

          pandas 1.5.0 开始,pandas.from_dummies 直接支持反向单热编码:

          import pandas as pd  # v 1.5.0
          
          onehot_df = pd.DataFrame({
              "monkey": [0, 1, 0],
              "rabbit": [1, 0, 0],
              "fox": [0, 0, 1]
          })
          
          new_df = pd.from_dummies(onehot_df)
          
          #          
          # 0  rabbit
          # 1  monkey
          # 2     fox
          

          生成的 DataFrame 似乎没有列标题(它是一个空字符串)。要解决此问题,rename from_dummies 之后的列

          new_df = pd.from_dummies(onehot_df).rename(columns={'': 'animal'})
          
          #    animal
          # 0  rabbit
          # 1  monkey
          # 2     fox
          

          或者,如果 DataFrame 已经用单独的列定义(如 pandas.get_dummies 生成的单热编码),例如

          import pandas as pd  # v 1.5.0
          
          onehot_df = pd.DataFrame({
              'animal_fox': [0, 0, 1],
              'animal_monkey': [0, 1, 0],
              'animal_rabbit': [1, 0, 0]
          })
          
          #    animal_fox  animal_monkey  animal_rabbit
          # 0           0              0              1
          # 1           0              1              0
          # 2           1              0              0
          

          只需指定 sep 即可反转编码

          new_df = pd.from_dummies(onehot_df, sep='_')
          
          #    animal
          # 0  rabbit
          # 1  monkey
          # 2     fox
          

          之前的字符串第一个例子sep 分隔符的一部分将成为新 DataFrame 中的列标题(在本例中为“animal”),字符串的其余部分将成为列值(在本例中为“rabbit”、“monkey”、“fox”) .

          【讨论】:

            【解决方案7】:

            尝试这个:

            df = pd.DataFrame({"monkey":[0,1,0,1,0],"rabbit":[1,0,0,0,0],"fox":[0,0,1,0,0], "cat":[0,0,0,0,1]})
            df 
            
               cat  fox  monkey  rabbit
            0    0    0       0       1
            1    0    0       1       0
            2    0    1       0       0
            3    0    0       1       0
            4    1    0       0       0
            
            pd.DataFrame([x for x in np.where(df ==1, df.columns,'').flatten().tolist() if len(x) >0],columns= (["animal"]) )
            
               animal
            0  rabbit
            1  monkey
            2     fox
            3  monkey
            4     cat
            

            【讨论】:

            • 我包括在更大数据帧的计时中。
            【解决方案8】:

            它可以通过简单地应用于数据框来实现

            # function to get column name with value one for each row in dataframe
            def get_animal(row):
                return(row.index[row.apply(lambda x: x==1)][0])
            
            # prepare a animal column
            df['animal'] = df.apply(lambda row:get_animal(row), axis=1)
            

            【讨论】:

              【解决方案9】:

              一种无需 for 循环即可处理多个标签的方法。结果将是一个列表列。如果每行中的标签数量相同,则可以添加 result_type='expand' 以获得多列。

              df.apply(lambda x: df.columns[x==1], axis=1)
              

              【讨论】:

                猜你喜欢
                • 2016-11-15
                • 2020-10-08
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2017-02-16
                • 1970-01-01
                • 1970-01-01
                • 2018-01-26
                相关资源
                最近更新 更多