pandas разделяет столбцы на несколько столбцов с переменной длиной [дубликат]

.*

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

Я также рассмотрел бы любое из следующих утверждений на веб-сайте:

"123 456 7890 until 6pm, then 098 765 4321"  
"123 456 7890 or try my mobile on 098 765 4321"  
"ex-directory - mind your own business"
22
задан user2900369 13 March 2015 в 15:33
поделиться

3 ответа

Использование s для вашего df['groups']:

In [21]: s = pd.Series({0: ['a', 'b', 'c'], 1:['c'], 2: ['b', 'c', 'e'], 3: ['a', 'c'], 4: ['b', 'e'] })

In [22]: s
Out[22]:
0    [a, b, c]
1          [c]
2    [b, c, e]
3       [a, c]
4       [b, e]
dtype: object

Это возможное решение:

In [23]: pd.get_dummies(s.apply(pd.Series).stack()).sum(level=0)
Out[23]:
   a  b  c  e
0  1  1  1  0
1  0  0  1  0
2  0  1  1  1
3  1  0  1  0
4  0  1  0  1

Логика этого:

  • .apply(Series) преобразует серию списков в dataframe
  • .stack() снова помещает все в один столбец (создавая многоуровневый индекс)
  • pd.get_dummies( ) создавая манекены
  • .sum(level=0) для объединения разных строк, которые должны быть одной строкой (путем суммирования второго уровня, сохраняя только исходный уровень (level=0))

Небольшой эквивалент pd.get_dummies(s.apply(pd.Series), prefix='', prefix_sep='').sum(level=0, axis=1)

Если это будет достаточно эффективно, я не знаю, но в любом случае, если производительность важна, сохранение списков в фрейме данных не очень хорошая идея.

29
ответ дан joris 20 August 2018 в 23:54
поделиться
  • 1
    Какую версию Панд вы используете? – Alex 13 March 2015 в 16:48
  • 2
    @joris, вероятно, это означало следующее: pd.get_dummies(s.apply(pd.Series), prefix='', prefix_sep='').sum(level=0, axis=1), поскольку ваш код выводит серию с суммой, а не фреймворком данных. – Primer 13 March 2015 в 16:49
  • 3
    Ах, извините, скобка оказалась не в том месте (стек должен быть в get_dummies). Я использую панды 0.15.2. @Primer Да, я написал это во-первых, но я нашел его со стеком немного более чистым (короче), но он дает точно такой же результат. – joris 13 March 2015 в 16:57
  • 4
    Ах, ладно, это работает для меня сейчас - удаляет меня. – Alex 13 March 2015 в 17:11
  • 5
    @Alex, вы начали с другого ввода (строка, которая форматируется как список, я начинаю с списка), но я не уверен, чего хочет OP. Кроме того, вы выполнили get_dummies в приложении (так что для каждой строки, а не один раз на всех), что сделало ее медленнее, как подход выше. – joris 13 March 2015 в 17:15

Несмотря на то, что на этот квест был дан ответ, у меня есть более быстрое решение:

df.groups.apply(lambda x: pd.Series([1] * len(x), index=x)).fillna(0, downcast='infer')

И если у вас есть пустые группы или NaN, вы можете просто:

df.loc[df.groups.str.len() > 0].apply(lambda x: pd.Series([1] * len(x), index=x)).fillna(0, downcast='infer')

Как это работает

Внутри лямбда x - ваш список, например ['a', 'b', 'c']. Таким образом, pd.Series будет выглядеть следующим образом:

In [2]: pd.Series([1, 1, 1], index=['a', 'b', 'c'])
Out[2]: 
a    1
b    1
c    1
dtype: int64

Когда все pd.Series объединяются, они становятся pd.DataFrame, а их index становятся columns; missing index стал column с NaN, как вы можете видеть дальше:

In [4]: a = pd.Series([1, 1, 1], index=['a', 'b', 'c'])
In [5]: b = pd.Series([1, 1, 1], index=['a', 'b', 'd'])
In [6]: pd.DataFrame([a, b])
Out[6]: 
     a    b    c    d
0  1.0  1.0  1.0  NaN
1  1.0  1.0  NaN  1.0

Теперь fillna заполняет те NaN с помощью 0:

In [7]: pd.DataFrame([a, b]).fillna(0)
Out[7]: 
     a    b    c    d
0  1.0  1.0  1.0  0.0
1  1.0  1.0  0.0  1.0

И downcast='infer' должен опуститься от float до int:

In [11]: pd.DataFrame([a, b]).fillna(0, downcast='infer')
Out[11]: 
   a  b  c  d
0  1  1  1  0
1  1  1  0  1

PS .: Не требуется использование .fillna(0, downcast='infer').

6
ответ дан Paulo Alves 20 August 2018 в 23:54
поделиться
  • 1
    Я тестировал ваше решение: он работает как шарм. Не могли бы вы прокомментировать его дальше, чтобы объяснить, как это работает? – Mike 12 June 2017 в 18:40
  • 2
    @Mike Я обновил свой ответ. Я надеюсь, что это помогает. – Paulo Alves 13 June 2017 в 13:05
  • 3
    А для добавления префикса к столбцам используйте: dummies.columns = ['D_'+col_name for col_name in dummies.columns] – Ufos 13 November 2017 в 00:06
  • 4
    @Ufos, вы могли бы просто .add_prefix('D_') – Paulo Alves 13 November 2017 в 11:19
  • 5
    @PauloAlves, ой! – Ufos 13 November 2017 в 13:57

Очень быстрое решение, если у вас большой размер данных

Использование sklearn.preprocessing.MultiLabelBinarizer

import pandas as pd
from sklearn.preprocessing import MultiLabelBinarizer

df = pd.DataFrame(
    {'groups':
        [['a','b','c'],
        ['c'],
        ['b','c','e'],
        ['a','c'],
        ['b','e']]
    }, columns=['groups'])

s = df['groups']

mlb = MultiLabelBinarizer()

pd.DataFrame(mlb.fit_transform(s),columns=mlb.classes_, index=df.index)

Результат:

    a   b   c   e
0   1   1   1   0
1   0   0   1   0
2   0   1   1   1
3   1   0   1   0
4   0   1   0   1

Работал для меня, а также был предложен здесь и здесь

2
ответ дан Teoretic 20 August 2018 в 23:54
поделиться
Другие вопросы по тегам:

Похожие вопросы: