【问题标题】:Dummify variables based on list of categories根据类别列表对变量进行虚拟化
【发布时间】:2018-01-10 01:01:30
【问题描述】:

例如,我有如下数据框。

>>> df
  CATX CATY CATZ
0    A    G  AAA
1    B    H  BBB
2    C    I  AAA
3    B    J  CCC
4    A    G  BBB
5    B    H  DDD
6    D    K  EEE
7    E    L  FFF

我想根据列表中提供的值在 df 上添加新列。例如,对于 CATZ,我有一个列表 ['AAA', 'BBB'],我需要考虑以表明观察值是 1 或 0,例如

>>> df
  CATX CATY CATZ  AAA  BBB
0    A    G  AAA    1    0
1    B    H  BBB    0    1
2    A    I  AAA    1    0
3    B    J  CCC    0    0
4    A    H  BBB    0    1
5    B    H  DDD    0    0
6    D    K  EEE    0    0
7    E    L  FFF    0    0

这与pd.get_dummies 有点不同,因为 get_dummies 会考虑整个数据框/列上的所有可能值(或 k-1 值)。目前,我正在做的是遍历列表并为每一行执行应用。

for catz_item in catz_list:
    df[catz_item] = df.apply(lambda x: 1 if x.CATZ == catz_item else 0, axis=1)

除了遍历列表之外还有其他方法可以做到这一点(因为这个循环有点慢)。为了使它更复杂,我也使用基于某个列表的 CATX 和 CATY 的组合来执行此操作,例如 [['A', 'G'], ['A', 'H'], [' B', 'H']].

--- 编辑---

CATX / CATY 组合输出

>>> df
  CATX CATY CATZ  AAA  BBB  AG  AH  BH
0    A    G  AAA    1    0   1   0   0
1    B    H  BBB    0    1   0   0   1
2    C    I  AAA    1    0   0   0   0
3    B    J  CCC    0    0   0   0   0
4    A    G  BBB    0    1   1   0   0
5    B    H  DDD    0    0   0   0   1
6    D    K  EEE    0    0   0   0   0
7    E    L  FFF    0    0   0   0   0

我现在使用的代码如下

catxy_list = [['A', 'G'], ['A', 'H'], ['B', 'H']]   
for catxy_item in catxy_list:
    df[catxy_item[0] + catxy_item[1]] = df.apply(lambda x: 1 if x.CATX == catxy_item[0] and x.CATY == catxy_item[1] else 0, axis=1)

【问题讨论】:

  • 您能否详细说明“使其更复杂”部分?您在那里的预期输出是什么?
  • @cᴏʟᴅsᴘᴇᴇᴅ,请参阅我对“复杂”部分的最新编辑。谢谢。
  • 谢谢,这很有帮助。如果需要,我已将其添加到我的答案中。
  • 感谢您的回答,我会做一些测试并接受适合我需要的答案,因为我需要为大约 10M 的观察进行此操作。
  • 嗯...在为复杂查询运行我的代码时,您可能会遭受内存爆裂...谢谢。我会尝试看看是否可以提出一种速度较慢但内存效率更高的技术。

标签: python pandas


【解决方案1】:

第一个bit涉及CATZ,可以使用where/mask + get_dummies -

v = df.CATZ.where(df.CATZ.isin(['AAA', 'BBB'])).str.get_dummies()

或者,

v = df.CATZ.mask(~df.CATZ.isin(['AAA', 'BBB'])).str.get_dummies()

接下来,对于您的“复杂查询”,使用 numpy 广播并在末尾进行 astype 转换 -

# initial values to compare
i = np.array([['A', 'G'], ['A', 'H'], ['B', 'H']])
# perform broadcasted comparison with `i` and convert the result to OHEs
j = (df.iloc[:, :-1].values[:, None] == i).all(2).astype(int)

# load the result into a dataframe  with the appropriate column names 
j = pd.DataFrame(j, columns=list(map(''.join, i)))

“复杂查询”的另一个较慢但内存效率更高的选项是遍历每个类别并找到 OHE:

ohe = []
for x, y in [['A', 'G'], ['A', 'H'], ['B', 'H']]:
    # generate OHEs for each pair of elements per category
    s = df.CATX.eq(x) & df.CATY.eq(y)  # s = df[['CATX', 'CATY']].isin([x, y]).all(1)
    s.name = ''.join([x, y])
    ohe.append(s)

# concatenate the intermediate results
j = pd.concat(ohe, 1).astype(int)

最后,您可以使用concatdfvj 加载到新的数据帧中。

pd.concat([df, v, j], 1)

  CATX CATY CATZ  AAA  BBB  AG  AH  BH
0    A    G  AAA    1    0   1   0   0
1    B    H  BBB    0    1   0   0   1
2    C    I  AAA    1    0   0   0   0
3    B    J  CCC    0    0   0   0   0
4    A    G  BBB    0    1   1   0   0
5    B    H  DDD    0    0   0   0   1
6    D    K  EEE    0    0   0   0   0
7    E    L  FFF    0    0   0   0   0

【讨论】:

    【解决方案2】:
    In [403]: df.join(df.CATZ.str.get_dummies())
    Out[403]:
      CATX CATY CATZ  AAA  BBB  CCC  DDD  EEE  FFF
    0    A    G  AAA    1    0    0    0    0    0
    1    B    H  BBB    0    1    0    0    0    0
    2    C    I  AAA    1    0    0    0    0    0
    3    B    J  CCC    0    0    1    0    0    0
    4    A    G  BBB    0    1    0    0    0    0
    5    B    H  DDD    0    0    0    1    0    0
    6    D    K  EEE    0    0    0    0    1    0
    7    E    L  FFF    0    0    0    0    0    1
    

    或:

    In [410]: df.join(df.CATZ[df.CATZ.isin(['AAA','BBB'])].str.get_dummies(), how='left').fillna(0)
    Out[410]:
      CATX CATY CATZ  AAA  BBB
    0    A    G  AAA  1.0  0.0
    1    B    H  BBB  0.0  1.0
    2    C    I  AAA  1.0  0.0
    3    B    J  CCC  0.0  0.0
    4    A    G  BBB  0.0  1.0
    5    B    H  DDD  0.0  0.0
    6    D    K  EEE  0.0  0.0
    7    E    L  FFF  0.0  0.0
    

    【讨论】:

    • 我看不出答案的第一部分有什么帮助。
    • @deadcode 对于那些有类似问题并需要该解决方案的人来说,保留它并没有什么坏处。
    • 同意。我只是想知道它是否在做除了 get_dummies 之外的任何事情。我猜这是连接的一步法。
    【解决方案3】:
    pd.crosstab(df.index,df.CATZ)[['AAA','BBB']]
    Out[66]: 
    CATZ   AAA  BBB
    row_0          
    0        1    0
    1        0    1
    2        1    0
    3        0    0
    4        0    1
    5        0    0
    6        0    0
    7        0    0
    
    pd.concat([df,pd.crosstab(df.index,df.CATZ)[['AAA','BBB']]],1)
    Out[68]: 
          CATX CATY CATZ  AAA  BBB
    row_0                         
    0        A    G  AAA    1    0
    1        B    H  BBB    0    1
    2        C    I  AAA    1    0
    3        B    J  CCC    0    0
    4        A    G  BBB    0    1
    5        B    H  DDD    0    0
    6        D    K  EEE    0    0
    7        E    L  FFF    0    0
    

    【讨论】:

    【解决方案4】:

    认为你需要两个np.where

    df["AAA"] = np.where(df["CATZ"] == "AAA", 1, 0)
    df["BBB"] = np.where(df["CATZ"] == "BBB", 1, 0)
    

    当标签很多时,这可能会很慢!

    【讨论】:

    • 对于 100 个列表项,他需要 100 个 np.where ;-)
    • @Wen 谢谢,Wen :P
    • @cᴏʟᴅsᴘᴇᴇᴅ 当有 100 个项目时,他可以使用 for 循环:P:P
    • 哇,循环? :-( 这完全是在回避和硬塞 np.where 的矢量化功能......不妨使用纯 python 函数 :D
    • 我现在一直在做的for循环,我发现它很慢。 :)
    猜你喜欢
    • 2020-09-14
    • 2021-12-31
    • 2018-11-06
    • 2012-09-29
    • 1970-01-01
    • 2018-07-15
    • 1970-01-01
    • 2019-05-19
    • 2021-05-13
    相关资源
    最近更新 更多