【问题标题】:Pandas create dummy features for each string in a dictionary of listsPandas 为列表字典中的每个字符串创建虚拟特征
【发布时间】:2018-05-26 05:50:51
【问题描述】:

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

获取这个 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']}

我们想为字典中的每个字符串和每个类别创建一个列/特征。如果字符串包含在 description 列中,则为 1,否则为 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 中可以有任意数量的字符串和类别,所以我想知道是否有其他方法可以做到这一点。

【问题讨论】:

  • 并非如此,如上例所示,我们希望添加 0/1 的整列,而不仅仅是关键字的计数。
  • 如果您只想测试category_acategory_b,可以使用快捷方式。如前所述,对于您的问题,我认为您无法比pd.Series.str.contains 优化更多(在pandas 技术范围内)。

标签: python pandas dummy-variable


【解决方案1】:

这是一个向量化的方法。主要观察结果是random_animals.description.str.contains 应用于字符串时会返回一系列指标,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

【讨论】:

    【解决方案2】:

    有趣的问题。我在下面编写了您想要的代码,但可能有更短的方法来做到这一点:

    #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)
    

    【讨论】:

      【解决方案3】:

      您可以扩展 pandas DataFrame 类并实现惰性列评估,如果派生列不存在,则实现逻辑并将其添加到基类列集合中。

      【讨论】:

        猜你喜欢
        • 2021-06-20
        • 1970-01-01
        • 2022-11-12
        • 1970-01-01
        • 2016-12-02
        • 1970-01-01
        • 2011-07-06
        • 2019-05-04
        • 2019-11-13
        相关资源
        最近更新 更多