在Pandas中的get_dummies之后保留NaN值

时间:2016-04-15 17:31:29

标签: python-3.x pandas

我有一个数据框' df'像这样 -

Id    v1    v2
0     A     0.23
1     B     0.65
2     NaN   0.87

如果我使用

df1 = get_dummies(df)
df1

我得到了

Id    v1_A    v1_B    v2
0     1       0       0.23
1     0       1       0.65
2     0       0       0.87 .

如何有效地获得以下内容?

Id    v1_A    v1_B    v2
0     1       0       0.23
1     0       1       0.65
2     NaN     NaN     0.87 .

我最初使用它,但需要太长时间

import numpy as np    
dfv1 = df[[v1]]    #Slicing the v1 column
dfs = get_dummies(dfv1)    
dfsum = dfs.apply(np.sum, axis=1)    #Calculating row by row sum of dfs
for i in range(dfs.size):    #Iterating over the entire dataframe
    if dfsum.iloc[i]==0:     #and if the sum is zero for some 'i'
        dfs.iloc[i][:]==np.nan    #changing corresponding row to NaN
del df['v1']    #Deleting original column
df = pandas.concat([df, dfs], axis=1)    #Appending the new one

我在Jupyter上使用Python 3.5.1,在Pandas上使用0.18。感谢。

2 个答案:

答案 0 :(得分:10)

方法#1将直接使用v1的nans,没有循环:

>>> df1 = pd.get_dummies(df)
>>> df1.loc[df.v1.isnull(), df1.columns.str.startswith("v1_")] = np.nan
>>> df1
   Id    v2  v1_A  v1_B
0   0  0.23   1.0   0.0
1   1  0.65   0.0   1.0
2   2  0.87   NaN   NaN

方法#2将使用dummy_na参数为我们提供一个我们可以使用的列:

>>> df1 = pd.get_dummies(df, dummy_na=True)
>>> df1
   Id    v2  v1_A  v1_B  v1_nan
0   0  0.23   1.0   0.0     0.0
1   1  0.65   0.0   1.0     0.0
2   2  0.87   0.0   0.0     1.0
>>> df1.loc[df1.v1_nan == 1, ["v1_A", "v1_B"]] = np.nan
>>> del df1["v1_nan"]
>>> df1
   Id    v2  v1_A  v1_B
0   0  0.23   1.0   0.0
1   1  0.65   0.0   1.0
2   2  0.87   NaN   NaN

答案 1 :(得分:0)

我将使用一个简单的数据框作为示例:

df1 = pd.DataFrame([['A', 'A'],[np.nan, 'B'], ['C', np.nan]])

>>> df1
     0    1
0    A    A
1  NaN    B
2    C  NaN

然后对其进行单热编码:

df1_ohe = pd.get_dummies(df1, dummy_na=True)

>>> df1_ohe
   0_A  0_C  0_nan  1_A  1_B  1_nan
0    1    0      0    1    0      0
1    0    0      1    0    1      0
2    0    1      0    0    0      1

现在获取这个数据框的一个子集,只包含 NaN 列:

nan_df = df1_ohe.loc[:, df1_ohe.columns.str.endswith("_nan")]

>>> nan_df
   0_nan  1_nan
0      0      0
1      1      0
2      0      1

最后,使用一些正则表达式并遍历数据框中的每一行和每个 NaN 列。

如果这个位置 [row, NaN column] 包含 1,那么原始数据框上的那个位置(在 OHE 之前)是一个 NaN。

因此,我使用正则表达式来识别原始列“col_id”(即,1_nan 给我 1,这是非 OHE 数据框中包含 NaN 的列)。

所以我定位包含该位置的所有列(即 1_A、1_B 和 1_nan)并用 NaN 替换它们的值。

pattern = "^([^_]*)_"
regex = re.compile(pattern)

for index in df1_ohe.index:
    for col_nan in nan_df.columns:
        if df1_ohe.loc[index,col_nan] == 1:
            col_id = regex.search(col_nan).group(1)
            targets = df1_ohe.columns[df1_ohe.columns.str.startswith(col_id+'_')]
            df1_ohe.loc[index, targets] = np.nan

给我:

>>> df1_ohe
   0_A  0_C  0_nan  1_A  1_B  1_nan
0  1.0  0.0    0.0  1.0  0.0    0.0
1  NaN  NaN    NaN  0.0  1.0    0.0
2  0.0  1.0    0.0  NaN  NaN    NaN

最后,我从 OHE 数据框中删除了 NaN 列

df1_ohe.drop(df1_ohe.columns[df1_ohe.columns.str.endswith('_nan')], axis=1, inplace=True)


>>> df1_ohe
   0_A  0_C  1_A  1_B
0  1.0  0.0  1.0  0.0
1  NaN  NaN  0.0  1.0
2  0.0  1.0  NaN  NaN