Я должен был oop? Есть ли более быстрый способ создания фиктивных переменных? - PullRequest
1 голос
/ 29 мая 2020

У меня есть некоторые данные о растениях, которые выглядят (но у меня до 7 атрибутов):

     Unnamed: 0     plant          att_1           att_2 ...
0            0     plant_a         sunlover        tall
1            1     plant_b         waterlover      sunlover
2            2     plant_c         fast growing    sunlover

Я пытался использовать pandas get_dummies, например:

df = pd.DataFrame({'A': ['a', 'b', 'a'], 'B': ['b', 'a', 'c'],'C': [1, 2, 3]})

pd.get_dummies(df, prefix=['col1', 'col2']):

.

 C  col1_a  col1_b  col2_a  col2_b  col2_c
 0  1       1       0       0       1       0
 1  2       0       1       1       0       0
 2  3       1       0       0       0       1

Но sunlover должен быть закодирован как 1, тем не менее, он находится в att_1 или att_2. Тогда у меня будет примерно 30 фиктивных переменных вместо 7 * 30 = 210 переменных. Я попытался l oop через весь набор и добавить значение для каждого манекена:

for count, plants in enumerate(data_plants.iterrows()):
  print("First", count, plants)
  for attribute in plants:
        print("Second", count, attribute)

Код просто печатается, потому что я видел проблему с тратой времени. Это работает, но его недостаточно для использования для 100 тыс. И более строк. Я подумал об использовании .value_counts () для получения атрибутов, а затем доступа к фиктивной переменной dataframe, чтобы обновить ее до 1, но затем я перезапишу атрибут. На данный момент я немного потерялся и у меня нет идей. Возможно, мне пришлось использовать другой пакет?

Цель будет примерно такой:

     Unnamed: 0     plant          att_1           att_2       sunlover      waterlover     tall  ...
0            0     plant_a         sunlover        tall        1             0              1
1            1     plant_b         waterlover      sunlover    1             1              0
2            2     plant_c         fast growing    sunlover    1             0              0

Ответы [ 2 ]

1 голос
/ 29 мая 2020

Используйте get_dummies с max:

c = ['att_1', 'att_2']
df1 = df.join(pd.get_dummies(df[c], prefix='', prefix_sep='').max(axis=1, level=0))
print (df1)
     plant         att_1     att_2  fast growing  sunlover  waterlover  tall
0  plant_a      sunlover      tall             0         1           0     1
1  plant_b    waterlover  sunlover             0         1           1     0
2  plant_c  fast growing  sunlover             1         1           0     0

Производительность для 3k строк, в реальных данных должна быть другая:

df = pd.concat([df] * 1000, ignore_index=True)


In [339]: %%timeit
     ...: 
     ...: c = ['att_1', 'att_2']
     ...: df1 = df.join(pd.get_dummies(df[c], prefix='', prefix_sep='').max(axis=1, level=0))
     ...: 
     ...: 
10.7 ms ± 1.11 ms per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [340]: %%timeit
     ...: attCols = df[['att_1', 'att_2']]
     ...: colVals = pd.Index(np.sort(attCols.stack().unique()))
     ...: def myDummies(row):
     ...:     return pd.Series(colVals.isin(row).astype(int), index=colVals)
     ...: 
     ...: df1 = df.join(attCols.apply(myDummies, axis=1))
     ...: 
     ...: 
1.03 s ± 22 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

Другое решение:

In [133]: %%timeit
     ...: c = ['att_1', 'att_2']
     ...: df1 = (df.join(pd.DataFrame([dict.fromkeys(x, 1) for x in df[c].to_numpy()])
     ...:                  .fillna(0)
     ...:                  .astype(np.int8)))
     ...:                  
13.1 ms ± 723 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
1 голос
/ 29 мая 2020

То, что вам нужно, только в некотором отношении похоже на get_dummies , но вам следует действовать другим путем.

Определите вид df , ограничено вашими столбцами «атрибутов»:

attCols = df[['att_1', 'att_2']]

В вашей целевой версии добавьте сюда другие столбцы «атрибутов».

Затем определите индекс, содержащий уникальные имена атрибутов:

colVals = pd.Index(np.sort(attCols.stack().unique()))

Третий шаг - определить функцию, вычисляющую результат для текущей строки:

def myDummies(row):
    return pd.Series(colVals.isin(row).astype(int), index=colVals)

И последний шаг - присоединить результат применения этой функции к каждой строке из attCols :

df = df.join(attCols.apply(myDummies, axis=1))

Результат для ваших данных примера:

     plant         att_1     att_2  fast growing  sunlover  tall  waterlover
0  plant_a      sunlover      tall             0         1     1           0
1  plant_b    waterlover  sunlover             0         1     0           1
2  plant_c  fast growing  sunlover             1         1     0           0
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...