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

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

有兴趣听听您的回复。

最佳答案

首先使用 get_dummies ,然后使用 groupby Tourn transform any ,转换为 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 的长度,结果并未解决性能问题,这将影响其中一些解决方案的计时。

关于python - Pandas 中的条件虚拟变量,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/48929349/

10-12 17:47