numpy/pandas: как преобразовать последовательность строк из нулей и единиц в матрицу

У меня есть данные, которые поступают в этом формате:

[
  (1, "000010101001010101011101010101110101", "aaa", ... ),
  (0, "111101010100101010101110101010111010", "bb", ... ),
  (0, "100010110100010101001010101011101010", "ccc", ... ),
  (1, "000010101001010101011101010101110101", "ddd", ... ),
  (1, "110100010101001010101011101010111101", "eeee", ... ),
  ...
]

В формате кортежа это выглядит так:

(Y, X, other_info, ... )

В конце дня мне нужно обучить классификатор (например, sklearn.linear_model.logistic.LogisticRegression), используя Y и X.

Какой самый простой способ превратить строку из нулей и единиц в нечто вроде np.array, чтобы я мог запустить его через классификатор? Похоже, здесь должен быть простой ответ, но я не смог придумать /google один.

Несколько заметок:

  • Я уже использую numpy/pandas/sklearn, поэтому все, что в этих библиотеках, является честной игрой.
  • Для большей части того, что я делаю, удобно иметь вместе столбцы other_info в DataFrame
  • Строки довольно длинные (~20000 столбцов), но общий фрейм данных не очень высокий (~500 строк).

2 ответа

Решение

Поскольку вы в первую очередь просили о способе преобразования строки из нулей и единиц в массив numpy, я предложу свое решение следующим образом:

d = '0101010000' * 2000 # create a 20,000 long string of 1s and 0s
d_array = np.fromstring(d, 'int8') - 48 # 48 is ascii 0. ascii 1 is 49

Это сравнительно выгодно для решения @DSM с точки зрения скорости:

In [21]: timeit numpy.fromstring(d, dtype='int8') - 48
10000 loops, best of 3: 35.8 us per loop

In [22]: timeit numpy.fromiter(d, dtype='int', count=20000)
100 loops, best of 3: 8.57 ms per loop

Как насчет чего-то вроде этого:

Сделайте фрейм данных:

In [82]: v = [
   ....:     (1, "000010101001010101011101010101110101", "aaa"),
   ....:     (0, "111101010100101010101110101010111010", "bb"),
   ....:     (0, "100010110100010101001010101011101010", "ccc"),
   ....:     (1, "000010101001010101011101010101110101", "ddd"),
   ....:     (1, "110100010101001010101011101010111101", "eeee"),
   ....:     ]

In [83]: 

In [83]: df = pandas.DataFrame(v)

Мы можем использовать fromiter или же array чтобы получить ndarray:

In [84]: d ="000010101001010101011101010101110101"

In [85]: np.fromiter(d, int) # better: np.fromiter(d, int, count=len(d))
Out[85]: 
array([0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0,
       1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1])

In [86]: np.array(list(d), int)
Out[86]: 
array([0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0,
       1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1])

Для этого может существовать плавный векторизованный способ, но я бы просто применил к значениям очевидную функцию для каждой записи и продолжил свой день:

In [87]: df[1]
Out[87]: 
0    000010101001010101011101010101110101
1    111101010100101010101110101010111010
2    100010110100010101001010101011101010
3    000010101001010101011101010101110101
4    110100010101001010101011101010111101
Name: 1

In [88]: df[1] = df[1].apply(lambda x: np.fromiter(x, int)) # better with count=len(x)

In [89]: df
Out[89]: 
   0                                                  1     2
0  1  [0 0 0 0 1 0 1 0 1 0 0 1 0 1 0 1 0 1 0 1 1 1 0 1    aaa
1  0  [1 1 1 1 0 1 0 1 0 1 0 0 1 0 1 0 1 0 1 0 1 1 1 0     bb
2  0  [1 0 0 0 1 0 1 1 0 1 0 0 0 1 0 1 0 1 0 0 1 0 1 0    ccc
3  1  [0 0 0 0 1 0 1 0 1 0 0 1 0 1 0 1 0 1 0 1 1 1 0 1    ddd
4  1  [1 1 0 1 0 0 0 1 0 1 0 1 0 0 1 0 1 0 1 0 1 0 1 1   eeee

In [90]: df[1][0]
Out[90]: 
array([0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0,
       1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1])
Другие вопросы по тегам