【问题标题】:How to create a dummy variable in Pandas Dataframe if a column matches certain values?如果列匹配某些值,如何在 Pandas Dataframe 中创建虚拟变量?
【发布时间】:2018-04-16 01:29:57
【问题描述】:

我有一个 Pandas 数据框,其中有一列 (ip) 具有某些值,另一个 Pandas 系列不在此 DataFrame 中,其中包含这些值的集合。如果给定行在我的 Pandas 系列 (black_ip) 中有其 ip,我想在 DataFrame 中创建一个列。

import pandas as pd

dict = {'ip': {0: 103022, 1: 114221, 2: 47902, 3: 23550, 4: 84644}, 'os': {0: 23, 1: 19, 2: 17, 3: 13, 4: 19}}

df = pd.DataFrame(dict)

df
     ip  os
0  103022  23
1  114221  19
2   47902  17
3   23550  13
4   84644  19

blacklist = pd.Series([103022, 23550])

blacklist

0    103022
1     23550

我的问题是:如何在df 中创建一个新列,这样当给定的ip 在黑名单中时显示为 1,否则显示为零?

对不起,如果这太愚蠢了,我还是编程新手。提前非常感谢!

【问题讨论】:

  • blacklist 值的明显长度是多少?
  • 它比 DataFrame 小很多。

标签: python python-3.x pandas dataframe


【解决方案1】:

isinastype 一起使用:

df['new'] = df['ip'].isin(blacklist).astype(np.int8)

也可以将列转换为categoricals:

df['new'] = pd.Categorical(df['ip'].isin(blacklist).astype(np.int8))

print (df)
       ip  os  new
0  103022  23    1
1  114221  19    0
2   47902  17    0
3   23550  13    1
4   84644  19    0

对于有趣的大 DataFrame 转换为 Categorical 不节省内存:

df = pd.concat([df] * 10000, ignore_index=True)

df['new1'] = pd.Categorical(df['ip'].isin(blacklist).astype(np.int8))
df['new2'] = df['ip'].isin(blacklist).astype(np.int8)
df['new3'] = df['ip'].isin(blacklist)
print (df.memory_usage())
Index        80
ip       400000
os       400000
new1      50096
new2      50000
new3      50000
dtype: int64

时间安排

np.random.seed(4545)

N = 10000
df = pd.DataFrame(np.random.randint(1000,size=N), columns=['ip'])
print (len(df))
10000

blacklist = pd.Series(np.random.randint(500,size=int(N/100)))
print (len(blacklist))
100

In [320]: %timeit df['ip'].isin(blacklist).astype(np.int8)
465 µs ± 21.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [321]: %timeit pd.Categorical(df['ip'].isin(blacklist).astype(np.int8))
915 µs ± 49.9 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [322]: %timeit pd.Categorical(df['ip'], categories = blacklist.unique()).notnull().astype(int)
1.59 ms ± 20.1 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [323]: %timeit df['new_column'] = [1 if x in blacklist.values else 0 for x in df.ip]
81.8 ms ± 2.72 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

【讨论】:

  • 感谢您的回答!如果我使用 uint8 而不是 int 有什么区别吗?
  • @RaulGuarini - 如果需要节省内存和大DataFrame :)
  • 是的,确实是这样。真正的数据框有 200 多条 MM 行和几列……只有分类数据。用它进行机器学习在内存消耗方面真的是一团糟!
【解决方案2】:

缓慢但简单易读的方法

另一种方法是使用list comprehension 创建新列,如果您的ip 值在blacklist 中,则设置为1,否则为0:

df['new_column'] = [1 if x in blacklist.values else 0 for x in df.ip]

>>> df
       ip  os  new_column
0  103022  23           1
1  114221  19           0
2   47902  17           0
3   23550  13           1
4   84644  19           0

编辑:在Categorical 上构建更快的方法:如果您想最大限度地提高速度,以下方法会非常快,尽管不如.isin 非分类方法快。它基于@jezrael 建议的pd.Categorical 的使用,但利用它分配类别的能力:

df['new_column'] = pd.Categorical(df['ip'], 
          categories = blacklist.unique()).notnull().astype(int)

时间安排:

import numpy as np
import pandas as pd
np.random.seed(4545)
N = 10000
df = pd.DataFrame(np.random.randint(1000,size=N), columns=['ip'])
blacklist = pd.Series(np.random.randint(500,size=int(N/100)))

%timeit df['ip'].isin(blacklist).astype(np.int8)
# 453 µs ± 8.81 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

%timeit pd.Categorical(df['ip'].isin(blacklist).astype(np.int8))
# 892 µs ± 17.6 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

%timeit pd.Categorical(df['ip'], categories = \
              blacklist.unique()).notnull().astype(int)
# 565 µs ± 32.4 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

【讨论】:

  • 你如何测试它?它似乎在小数据或重复。更好的是这里不转换为分类,那么返回 %timeit (df['ip'].isin(blacklist).astype(np.int8) 呢?
  • 请检查我的时间,我对你的时间感到惊讶,所以尝试使用大数据创建。
  • 就像我在回答中所说,您的isin 方法是最快的:)。我在你更大的数据集上重新运行了我的计时,我会更新我的计时,一秒
  • 在我的机器上,当我在转换为 Categorical 时分配类别时,我仍然获得了性能提升,但似乎我们得到了不同的结果......
  • 是的,我也很惊讶。我在windows下使用pandas 0.22.0、python 3.5。你呢?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-20
  • 2020-03-11
  • 1970-01-01
  • 2012-09-27
  • 1970-01-01
  • 2021-12-31
相关资源
最近更新 更多