Панды создают фиктивные функции для каждой строки в словаре списков - PullRequest
0 голосов
/ 24 мая 2018

Реализация следующей логики для целей разработки функций.Простой подход прост, но интересно, есть ли более эффективное решение, о котором каждый может подумать.Идеи приветствуются, если вам не хочется реализовывать весь код!

Возьмите этот 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']}

Мы хотим создать столбец / функцию для каждой строки в словаре Идля каждой категории.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 может быть произвольное количество строк и категорий, поэтому мне интересно, есть ли способ сделатьэто иначе.

Ответы [ 3 ]

0 голосов
/ 25 мая 2018

Интересная проблема.Ниже я написал то, что вы хотите, но, вероятно, есть более короткий способ сделать это:

#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)
0 голосов
/ 26 мая 2018

Вот векторизованный метод.Основное наблюдение состоит в том, что 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
0 голосов
/ 25 мая 2018

Вы можете расширить класс DataFrame pandas и реализовать оценку отложенных столбцов, где, если производный столбец не существует, реализовать логику и добавить ее в коллекцию столбцов базового класса.

...