2

我正在和熊猫一起工作。我的目标是将数据框中的几列从包含 NaN 或字符串数​​据转换为或多或少的虚拟变量(NaN 为 0;任何字符串为 1)。我想在不使用完整的字符串列表并替换它们的情况下执行此操作,因为存在拼写错误,这会导致错误。我已经能够使用 fillna 函数将所有 NaN 数据替换为 0,这就像做梦一样!

我希望有类似的东西可以用 1 替换所有字符串数据,但保留 0。我搜索了stackoverflow和其他地方,但收效甚微。

数据大致如下所示,我只希望它适用于以 T_ 开头的列:

    fol    T_opp    T_Dir    T_Enh   Activity
    1      0        0        vo      hf
    2      vr       0        0       hx
    2      0        0        0       fe
    3      0        bt       0       rn

我希望输出看起来相同,但将“vr”、“bt”和“vo”分别替换为整数 1。据我所知,pd get_dummies 函数不是我想要的。我也无法使用replace() 来完成这项工作。我尝试了使用 T/F 掩码和零列表的方法,但结果非常错误,我不会费心在此处发布代码。

编辑:我在上面的玩具数据中添加了一个额外的列。“活动”列是一些我不想触摸的数据,也是字符串。

4

2 回答 2

3

您可以DataFrame.replace()使用正则表达式执行此操作:

In [14]: df
Out[14]:
   fol T_opp T_Dir T_Enh
0    1     0     0    vo
1    2    vr     0     0
2    2     0     0     0
3    3     0    bt     0

In [15]: df.replace(regex={'vr|bt|vo': '1'}).convert_objects(convert_numeric=True)
Out[15]:
   fol T_opp T_Dir T_Enh
0    1     0     0     1
1    2     1     0     0
2    2     0     0     0
3    3     0     1     0

如果由于某种原因你反对dicts,你也可以非常明确地表达:

In [19]: df.replace(regex='vr|bt|vo', value='1')
Out[19]:
   fol T_opp T_Dir T_Enh
0    1     0     0     1
1    2     1     0     0
2    2     0     0     0
3    3     0     1     0

但是等等还有更多!您可以通过传递嵌套来指定要操作的列dict(键不能是正则表达式,好吧,它们可以,但除了返回框架外不会做任何事情):

In [22]: df.replace({'T_opp': {'vr': 1}, 'T_Dir': {'bt': 1}})
Out[22]:
   fol T_opp T_Dir T_Enh
0    1     0     0    vo
1    2     1     0     0
2    2     0     0     0
3    3     0     1     0

编辑:由于您用数字替换所有字符串1(根据您在下面的评论),请执行以下操作:

In [23]: df.replace(regex={r'\D+': 1})
Out[23]:
   fol T_opp T_Dir T_Enh
0    1     0     0     1
1    2     1     0     0
2    2     0     0     0
3    3     0     1     0

编辑:微基准测试在这里可能有用:

安迪的方法(更快):

In [11]: timeit df.convert_objects(convert_numeric=True).fillna(1)
1000 loops, best of 3: 590 µs per loop

DataFrame.replace()

In [46]: timeit df.replace(regex={r'\D': 1})
1000 loops, best of 3: 801 µs per loop

如果您有包含要保留的字符串的列

In [45]: cols_to_replace = 'T_opp', 'T_Dir', 'T_Enh'

In [46]: d = dict(zip(cols_to_replace, [{r'\D': 1}] * len(cols_to_replace)))

In [47]: d
Out[47]: {'T_Dir': {'\\D': 1}, 'T_Enh': {'\\D': 1}, 'T_opp': {'\\D': 1}}

In [48]: df.replace(d)
Out[48]:
   fol T_opp T_Dir T_Enh Activity
0    1     0     0     1       hf
1    2     1     0     0       hx
2    2     0     0     0       fe
3    3     0     1     0       rn

另一种方法是filter在替换后使用并将结果连接在一起:

In [10]: df
Out[10]:
   fol T_opp T_Dir T_Enh Activity
0    1     0     0    vo       hf
1    2    vr     0     0       hx
2    2     0     0     0       fe
3    3     0    bt     0       rn

In [11]: filtered = df.filter(regex='T_.+')

In [12]: res = filtered.replace({'\D': 1})

In [13]: res
Out[13]:
  T_opp T_Dir T_Enh
0     0     0     1
1     1     0     0
2     0     0     0
3     0     1     0

In [14]: not_filtered = df[df.columns - filtered.columns]

In [15]: not_filtered
Out[15]:
  Activity  fol
0       hf    1
1       hx    2
2       fe    2
3       rn    3

In [16]: res.join(not_filtered)
Out[16]:
  T_opp T_Dir T_Enh Activity  fol
0     0     0     1       hf    1
1     1     0     0       hx    2
2     0     0     0       fe    2
3     0     1     0       rn    3

请注意,不保留列的原始顺序。

您可以使用正则表达式来搜索列名,如果要保留许多列,这可能比显式构造列表更有用。运算符在与两个对象 ( is an ) 一起使用-时执行集差。Indexdf.columnsIndex

DataFrame.convert_objects()除非您的列是混合的字符串/整数列,否则您可能需要稍后调用。我的解决方案假设它们都是字符串,所以我调用convert_objects()将值强制为int dtype.

于 2013-10-04T22:46:47.280 回答
2

另一种选择是反过来做,首先转换为数字:

In [11]: df.convert_objects(convert_numeric=True)
Out[11]: 
   fol  T_opp  T_Dir  T_Enh Activity
0    1      0      0    NaN       hf
1    2    NaN      0      0       hx
2    2      0      0      0       fe
3    3      0    NaN      0       rn

然后用 1 填充 NaN:

In [12]: df.convert_objects(convert_numeric=True).fillna(1)
Out[12]: 
   fol  T_opp  T_Dir  T_Enh Activity
0    1      0      0      1       hf
1    2      1      0      0       hx
2    2      0      0      0       fe
3    3      0      1      0       rn
于 2013-10-04T22:50:29.750 回答