【问题标题】:Conditional dummy variables in PandasPandas 中的条件虚拟变量
【发布时间】:2018-08-02 10:01:28
【问题描述】:
df.head()

Player  Tourn   Score
Tom      a       65 
Henry    a       72 
Johno    a       69 
Ingram   a       79 
Ben      a       76 
Harry    a       66 
Nick     b       70
Ingram   b       79 
Johno    b       69

我有一个玩家在各种锦标赛中得分的数据框(“a”到“m”)。有些球员参加了多场比赛,有些球员只参加了一场比赛。我希望为每个玩家创建一个额外的列,如果该玩家参加了该锦标赛,则为 1,如果他没有参加,则为 0(所以基本上是一个虚拟变量)。

看起来像这样(对每个玩家重复):

Player  Tourn   Score  Tom(Dummy)
Tom      a       65       1
Henry    a       72       1
Johno    a       69       1
Ingram   a       79       1
Ben      a       76       1
Harry    a       66       1
Nick     b       70       0
Ingram   b       79       0
Johno    b       69       0

在代码中实现这一目标的最佳方法是什么? (理想情况下,我需要能够在大型数据帧中很好地扩展的东西!)

有兴趣听到您的回复。

【问题讨论】:

  • 我知道这与问题无关,但我最初将问题读作“大陆老熊猫”...我需要咖啡

标签: python pandas dataframe dummy-variable


【解决方案1】:

首先使用get_dummies,然后按列Tourn 使用groupbyanytransform,转换为int,最后将join 转换为原始:

df1 = pd.get_dummies(df['Player'])
df2 = df.join(df1.groupby(df['Tourn']).transform('any').astype(int))

另一种更快的解决方案(对于每个锦标赛,每个玩家只玩一次):

df.join(df.groupby(['Tourn','Player']).size().unstack(fill_value=0), on='Tourn')

print (df2)
   Player Tourn  Score  Ben  Harry  Henry  Ingram  Johno  Nick  Tom
0     Tom     a     65    1      1      1       1      1     0    1
1   Henry     a     72    1      1      1       1      1     0    1
2   Johno     a     69    1      1      1       1      1     0    1
3  Ingram     a     79    1      1      1       1      1     0    1
4     Ben     a     76    1      1      1       1      1     0    1
5   Harry     a     66    1      1      1       1      1     0    1
6    Nick     b     70    0      0      0       1      1     1    0
7  Ingram     b     79    0      0      0       1      1     1    0
8   Johno     b     69    0      0      0       1      1     1    0

时间安排

N = 10000
a = ['Tom', 'Henry', 'Johno', 'Ingram', 'Ben', 'Harry', 'Nick', 'Ingram', 'Johno']
a = ['{}{}'.format(i, j) for i in range(5) for j in a]

df = pd.DataFrame({'Player':np.random.choice(a, size=N), 
                   'Tourn':np.random.randint(1000, size=N).astype(str)})

df = df.sort_values('Tourn')
#print (df.head())

In [486]: %%timeit
     ...: df.join(df.groupby(['Tourn','Player']).size().unstack(fill_value=0), on='Tourn')
     ...: 
100 loops, best of 3: 12.6 ms per loop

In [487]: %%timeit 
     ...: df.join(pd.crosstab(df.Tourn, df.Player), on='Tourn')
10 loops, best of 3: 60.9 ms per loop

In [488]: %%timeit
     ...: df1 = pd.get_dummies(df['Player'])
     ...: df2 = df.join(df1.groupby(df['Tourn']).transform('any').astype(int))
     ...: 
10 loops, best of 3: 120 ms per loop

In [489]: %%timeit
     ...: df.join(pd.get_dummies(df.Tourn).T.dot(pd.get_dummies(df.Player)), on='Tourn')
     ...: 
1 loop, best of 3: 895 ms per loop

In [490]: %%timeit
     ...: dd = df.Tourn.str.get_dummies()
     ...: df.assign(**{x.Player: dd[x.Tourn] for x in df.itertuples()})
     ...: 
1 loop, best of 3: 7.02 s per loop

In [491]: %%timeit
     ...: df.assign(**{x.Player:df.Tourn.eq(x.Tourn).astype(int) for x in df.itertuples()})
     ...: 
1 loop, best of 3: 13.7 s per loop

警告

考虑到DataFrame 的组数和长度,结果并未解决性能问题,这将影响其中一些解决方案的时间安排。

【讨论】:

    【解决方案2】:

    pd.get_dummiespd.DataFrame.dotpd.DataFrame.join强>

    我使用dot 来执行交叉制表。我对其进行了设计,使Tourn 值最终出现在索引中,并允许我在该列上使用join

    df.join(pd.get_dummies(df.Tourn).T.dot(pd.get_dummies(df.Player)), on='Tourn')
    
       Player Tourn  Score  Ben  Harry  Henry  Ingram  Johno  Nick  Tom
    0     Tom     a     65    1      1      1       1      1     0    1
    1   Henry     a     72    1      1      1       1      1     0    1
    2   Johno     a     69    1      1      1       1      1     0    1
    3  Ingram     a     79    1      1      1       1      1     0    1
    4     Ben     a     76    1      1      1       1      1     0    1
    5   Harry     a     66    1      1      1       1      1     0    1
    6    Nick     b     70    0      0      0       1      1     1    0
    7  Ingram     b     79    0      0      0       1      1     1    0
    8   Johno     b     69    0      0      0       1      1     1    0
    

    无耻的插头

    Post on pivoting for additional ways to crosstab

    【讨论】:

    • 好主意,数学家的想法有点不同,我喜欢它;)
    【解决方案3】:

    你可以的

    选项 1 -- 源自 piRSquared 的点

    In [990]: df.join(pd.crosstab(df.Tourn, df.Player), on='Tourn')
    Out[990]:
       Player Tourn  Score  Ben  Harry  Henry  Ingram  Johno  Nick  Tom
    0     Tom     a     65    1      1      1       1      1     0    1
    1   Henry     a     72    1      1      1       1      1     0    1
    2   Johno     a     69    1      1      1       1      1     0    1
    3  Ingram     a     79    1      1      1       1      1     0    1
    4     Ben     a     76    1      1      1       1      1     0    1
    5   Harry     a     66    1      1      1       1      1     0    1
    6    Nick     b     70    0      0      0       1      1     1    0
    7  Ingram     b     79    0      0      0       1      1     1    0
    8   Johno     b     69    0      0      0       1      1     1    0
    

    选项 2

    In [976]: df.assign(**{x.Player:df.Tourn.eq(x.Tourn).astype(int) for x in df.itertuples()})
    Out[976]:
       Player Tourn  Score  Ben  Harry  Henry  Ingram  Johno  Nick  Tom
    0     Tom     a     65    1      1      1       0      0     0    1
    1   Henry     a     72    1      1      1       0      0     0    1
    2   Johno     a     69    1      1      1       0      0     0    1
    3  Ingram     a     79    1      1      1       0      0     0    1
    4     Ben     a     76    1      1      1       0      0     0    1
    5   Harry     a     66    1      1      1       0      0     0    1
    6    Nick     b     70    0      0      0       1      1     1    0
    7  Ingram     b     79    0      0      0       1      1     1    0
    8   Johno     b     69    0      0      0       1      1     1    0
    

    选项 3

    In [979]: dd = df.Tourn.str.get_dummies()
    
    In [980]: df.assign(**{x.Player: dd[x.Tourn] for x in df.itertuples()})
    Out[980]:
       Player Tourn  Score  Ben  Harry  Henry  Ingram  Johno  Nick  Tom
    0     Tom     a     65    1      1      1       0      0     0    1
    1   Henry     a     72    1      1      1       0      0     0    1
    2   Johno     a     69    1      1      1       0      0     0    1
    3  Ingram     a     79    1      1      1       0      0     0    1
    4     Ben     a     76    1      1      1       0      0     0    1
    5   Harry     a     66    1      1      1       0      0     0    1
    6    Nick     b     70    0      0      0       1      1     1    0
    7  Ingram     b     79    0      0      0       1      1     1    0
    8   Johno     b     69    0      0      0       1      1     1    0
    

    【讨论】:

    • 我真的很好奇循环解决方案是否很快。似乎没有。
    【解决方案4】:

    遇到了类似的问题并找到了最佳解决方案。 感谢https://www.ritchieng.com/pandas-creating-dummy-variables/

    在你的情况下,答案应该是:

    df['Tom(Dummy)'] = df.Tourn.map({'b':0, 'a':1}) 
    

    读作:

    # using .map to create dummy variables
    # df['category_name  or new Dummy var. name '] = df.Category.map({'unique_term':0, 'unique_term2':1}) 
    

    希望对你有帮助!

    【讨论】:

      猜你喜欢
      • 2019-06-23
      • 1970-01-01
      • 2012-07-20
      • 1970-01-01
      • 2018-10-18
      • 1970-01-01
      • 1970-01-01
      • 2018-03-22
      • 2016-11-30
      相关资源
      最近更新 更多