Pandas 为列表字典中的每个字符串创建虚拟特征

Pandas create dummy features for each string in a dictionary of lists

为特征工程目的实施以下逻辑。一个简单的方法很容易,但想知道是否有任何人都能想到的更有效的解决方案。如果您不想实现整个代码,我们将不胜感激!

取这个DataFrame和字典

import pandas as pd
random_animals = pd.DataFrame(
                {'description':['xdogx','xcatx','xhamsterx','xdogx'
                                ,'xhorsex','xdonkeyx','xcatx']
                })


cat_dict = {'category_a':['dog','cat']
            ,'category_b':['horse','donkey']}

我们想为字典中的每个字符串和每个类别创建一个 column/feature。 1 如果字符串包含在 description 列中 0 否则。

所以这个玩具示例的输出如下所示:

  description  is_dog is_cat is_horse is_donkey is_category_a is_category_b
0       xdogx       1      0        0         0             1             0
1       xcatx       0      1        0         0             1             0    
2   xhamsterx       0      0        0         0             0             0
3       xdogx       1      0        0         0             1             0
4     xhorsex       0      0        1         0             0             1
5    xdonkeyx       0      0        0         1             0             1
6       xcatx       0      1        0         0             1             0

简单的方法是为每个需要的输出列迭代一次 运行(对于每一列,为了简单起见,这里只是硬编码 is_dog)

random_animals['is_dog'] = random_animals['description'].str.contains('dog')*1

cat_dict 中可以有任意数量的字符串和类别,所以我想知道是否有其他方法可以做到这一点。

您可以扩展 pandas DataFrame class 并实施惰性列评估,如果派生列不存在,则实施逻辑并将其添加到基础 class 列collection.

有趣的问题。在下面编写您想要的代码,但可能有更短的方法:

#Creating the DataFrame with columns of zeros

names = [x[1:-1] for x in random_animals.description.unique()]
categories = list(cat_dict.keys())
columns = names + categories
df_names = pd.DataFrame(0, index=np.arange(len(random_animals)), 
columns=columns)
df = pd.concat([random_animals, df_names], axis = 1)

#Populating the Dataframe - Automating your solution

#For animal names
for i in range(len(df.columns)-1):
    df[df.columns[i+1]] = df['description'].str.contains(df.columns[i+1])*1

#For categories
if df.columns[i+1] in list(cat_dict.keys()):
    searchfor = cat_dict[df.columns[i+1]]
    df[df.columns[i+1]]= df['description'].str.contains('|'.join(searchfor))*1

#Finally renaming names pattern of columns from "dog" to "is_dog"...:

for column in df.columns:
 if column in names:
     column_new = "is_"+column
     df[column_new] = df[column]
     df = df.drop(column, axis =1)

这是一个向量化的方法。主要观察是 random_animals.description.str.contains 应用于字符串时 returns 一系列指标,每行一个指标 random_animals.

由于random_animals.description.str.contains本身就是一个向量化函数,我们可以将其应用到动物集合中,得到一个完整的指标矩阵。

最后,我们可以通过在不同列之间强制执行逻辑来添加类别。这可能比多次检查字符串包含更快。

import pandas as pd
random_animals = pd.DataFrame(
                {'description':['xdogx','xcatx','xhamsterx','xdogx'
                                ,'xhorsex','xdonkeyx','xcatx']
                })


cat_dict = {'category_a':['dog', 'cat']
            ,'category_b':['horse', 'donkey']}

# create a Series containing all individual animals (without duplicates)
animals = pd.Series([animal for v in cat_dict.values()
        for animal in v])

df = pd.DataFrame(
        animals.apply(random_animals.description.str.contains).T.values,
        index  = random_animals.description,
        columns = animals).astype(int)

for cat, animals in cat_dict.items():
    df[cat] = df[animals].any(axis=1).astype(int)

             # dog  cat  horse  donkey  category_a  category_b
# description
# xdogx          1    0      0       0           1           0
# xcatx          0    1      0       0           1           0
# xhamsterx      0    0      0       0           0           0
# xdogx          1    0      0       0           1           0
# xhorsex        0    0      1       0           0           1
# xdonkeyx       0    0      0       1           0           1
# xcatx          0    1      0       0           1           0