Разбить столбец dataframe на несколько строк (TypeError: невозможно привести данные массива из dtype ('int64') в dtype ('int32'))

Я попытаюсь сделать кадр данных с этими данными:

test1   test2                 test3
test    [test1, test2]        [testbelongsto1, testbelongst2]

Что-то вроде этого:

test1   test2                 test3
test    test1                 testbelongsto1
test    test2                 testbelongsto2

Я нашел ответ на этот вопрос https://stackoverflow.com/a/38652414 Выглядит именно то, что мне нужно, верно? Есть много вопросов, которые отвечают на мой вопрос ..

Однако, что бы я ни пытался, я застрял с этой ошибкой:

TypeError: Cannot cast array data from dtype('int64') to dtype('int32') according to the rule 'safe'

с этой функцией (см. ссылку):

 def explode(self, df, columns):
    idx = np.repeat(df.index, df[columns[0]].str.len())
    a = df.T.reindex_axis(columns).values
    concat = np.concatenate([np.concatenate(a[i]) for i in range(a.shape[0])])
    p = pd.DataFrame(concat.reshape(a.shape[0], -1).T, idx, columns)
    return pd.concat([df.drop(columns, axis=1), p], axis=1).reset_index(drop=True)

Важная заметка! дата исходит из функции read_csv. Столбцы, которые мне нужно взорвать, представляют собой строки, поэтому я написал этот фрагмент кода, чтобы преобразовать их в списки:

   df['users'] = df['users'].apply(literal_eval)

Все перепробовал с конвертацией из dtype в сохранение их в других форматах. Но ничего не решает проблему...

Пожалуйста помоги

ОБНОВЛЕНИЕ: Ниже показан «реальный» пример набора данных из нескольких строк: «test2» => «users» и «test3» => «interests», массивы имеют одинаковый размер.

{'index': [0, 1, 2, 3, 4], 'Unnamed: 0': [0, 1, 4, 5, 6], 'users': ['[1, 1, 28, 28, 68]', '[1, 1, 16]', '[32, 37, 66, 67, 54, 117]', '[31, 37, 66, 67, 100, 113, 117]', '[32, 37, 66, 67, 54, 117]'], 'interests': ['[set(), set(), set(), set(), set()]', '[set(), set(), set()]', '[set(), set(), set(), set(), {1535, 1542, 1527}, set()]', '[set(), set(), set(), set(), set(), set(), set()]', '[set(), set(), set(), set(), {1535, 1542, 1527}, set()]']}

ОБНОВЛЕНИЕ 2: Хорошо, это именно то, чего я хочу. Текущие данные, которые я получил сейчас:

`
index       lift        confidence         interests         users
0                                          {333, 333}        1   
0                                          set()             22
0                                          set()             77
0           0           0.75               set()             88
4                                          set()             33
4           3           0.50               set()             44
`

Таким образом, кажется, что добавляется только последняя из каждой итерации. Это то, что я хочу:

`
index       lift        confidence         interests         users
0           88          0.33               344,              1  
0           88          0.33               333               1   
0           88          0.33               set()             22
0           88          0.33               set()             77
0           88          0.33               set()             88
4           38          0.50               set()             33
4           38          0.50               set()             44
`

Итак, я хочу, чтобы каждая строка данных (серия) повторялась для каждого пользователя, а также интересы каждого пользователя.


person iLuvCode    schedule 22.07.2017    source источник
comment
Можете ли вы попробовать обновить pandas/numpy до последних версий? Потому что это похоже на ошибку...   -  person jezrael    schedule 22.07.2017
comment
Пожалуйста, опубликуйте df.reset_index().head().to_dict('list'), чтобы мы могли увидеть однозначное представление нескольких строк вашего DataFrame. Возможно, тогда мы сможем воспроизвести ошибку, которую вы видите.   -  person unutbu    schedule 22.07.2017
comment
@jezrael Я попробовал это сейчас, но все еще получаю сообщение об ошибке   -  person iLuvCode    schedule 22.07.2017
comment
Я только пытаюсь, извините. А MaxU ответ работает?   -  person jezrael    schedule 22.07.2017
comment
@unutbu В мой первоначальный ответ добавлен «настоящий» набор данных.   -  person iLuvCode    schedule 22.07.2017


Ответы (1)


Если вы можете быть уверены, что ваши данные не содержат вредоносных строк, вы можете преобразовать строки в Объекты Python, использующие eval. Однако будьте очень осторожны — оценка вредоносных строк теоретически может запускать произвольный код на вашем компьютере!

Выделив опасность eval, вы можете проанализировать и изменить свой DataFrame, используя apply(pd.Series) трюк:

import pandas as pd

df = pd.DataFrame({'test': [0, 1, 4, 5, 6], 'test2': [0, 10, 40, 50, 60], 'users': ['[1, 1, 28, 28, 68]', '[1, 1, 16]', '[32, 37, 66, 67, 54, 117]', '[31, 37, 66, 67, 100, 113, 117]', '[32, 37, 66, 67, 54, 117]'], 'interests': ['[set(), set(), set(), set(), set()]', '[set(), set(), set()]', '[set(), set(), set(), set(), {1535, 1542, 1527}, set()]', '[set(), set(), set(), set(), set(), set(), set()]', '[set(), set(), set(), set(), {1535, 1542, 1527}, set()]']})

for col in df.columns.difference(['test', 'test2']):
    df[col] = df[col].apply(eval)

interests = df['interests'].apply(pd.Series)
interests = interests.stack().apply(lambda x: pd.Series(list(x)))
users = df['users'].apply(pd.Series)
users = users.stack()

result = pd.concat({'users': users, 'interests':interests}, axis=1)
result = result.stack() 
result['users'] = result['users'].ffill()
result.index = result.index.droplevel(level=[1,2])
result = df.drop(['interests','users'], axis=1).join(result)
print(result)

урожаи

   test  test2  interests  users
0     0      0        NaN    1.0
0     0      0        NaN    1.0
0     0      0        NaN   28.0
0     0      0        NaN   28.0
0     0      0        NaN   68.0
1     1     10        NaN    1.0
1     1     10        NaN    1.0
1     1     10        NaN   16.0
2     4     40        NaN   32.0
2     4     40        NaN   37.0
2     4     40        NaN   66.0
2     4     40        NaN   67.0
2     4     40     1535.0   54.0
2     4     40     1542.0   54.0
2     4     40     1527.0   54.0
2     4     40        NaN  117.0
3     5     50        NaN   31.0
3     5     50        NaN   37.0
3     5     50        NaN   66.0
3     5     50        NaN   67.0
3     5     50        NaN  100.0
3     5     50        NaN  113.0
3     5     50        NaN  117.0
4     6     60        NaN   32.0
4     6     60        NaN   37.0
4     6     60        NaN   66.0
4     6     60        NaN   67.0
4     6     60     1535.0   54.0
4     6     60     1542.0   54.0
4     6     60     1527.0   54.0
4     6     60        NaN  117.0

Основная идея состоит в том, чтобы использовать apply(pd.Series) для «разбиения» списков на столбцы:

In [572]: interests = df['interests'].apply(pd.Series); interests
Out[572]: 
    0   1   2    3                   4    5    6
0  {}  {}  {}   {}                  {}  NaN  NaN
1  {}  {}  {}  NaN                 NaN  NaN  NaN
2  {}  {}  {}   {}  {1535, 1542, 1527}   {}  NaN
3  {}  {}  {}   {}                  {}   {}   {}
4  {}  {}  {}   {}  {1535, 1542, 1527}   {}  NaN

Поскольку вы также хотите «взорвать» наборы, примените трюк pd.Series во второй раз:

In [573]: interests = interests.stack().apply(lambda x: pd.Series(list(x))); interests
Out[573]: 
          0       1       2
0 0     NaN     NaN     NaN
  1     NaN     NaN     NaN
  2     NaN     NaN     NaN
  3     NaN     NaN     NaN
  4     NaN     NaN     NaN
1 0     NaN     NaN     NaN
  1     NaN     NaN     NaN
  2     NaN     NaN     NaN
2 0     NaN     NaN     NaN
  1     NaN     NaN     NaN
  2     NaN     NaN     NaN
  3     NaN     NaN     NaN
  4  1535.0  1542.0  1527.0
  ...

Сделав то же самое для столбца users, объедините оба кадра данных в один:

result = pd.concat({'users': users, 'interests':interests}, axis=1)

Переместите уровень индекса внутреннего столбца в индекс и заполните столбец users вперед, чтобы распространять значения users, когда у пользователя есть несколько интересов:

result = result.stack() 
result['users'] = result['users'].ffill()
#        interests  users
# 0 0 0        NaN    1.0
#   1 0        NaN    1.0
#   2 0        NaN   28.0
#   3 0        NaN   28.0
#   4 0        NaN   68.0
# 1 0 0        NaN    1.0
#   1 0        NaN    1.0
#   2 0        NaN   16.0
# 2 0 0        NaN   32.0
#   1 0        NaN   37.0
#   2 0        NaN   66.0
#   3 0        NaN   67.0
#   4 0     1535.0   54.0
#     1     1542.0   54.0
#     2     1527.0   54.0
# ...

Наконец, отбросьте 2 самых внутренних уровня индекса и соедините result обратно с df:

result.index = result.index.droplevel(level=[1,2])
result = df.drop(['interests','users'], axis=1).join(result)
person unutbu    schedule 22.07.2017
comment
Спасибо за ваш ответ, что такое столбец «тест»? Это то же значение, что и у unnamed: 0, но нет доступа к столбцу;) @unutbu - person iLuvCode; 22.07.2017
comment
решил эту проблему: df['index'] = df['Unnamed: 0'] теперь я пробую ваш код - person iLuvCode; 22.07.2017
comment
Я получаю следующую ошибку: TypeError: eval() arg 1 must be a string, bytes or code object @unutbu Помимо этих двух столбцов я также получил другие данные, можно ли повторить эти столбцы, когда я пытаюсь это сделать, теперь они просто пусты? - person iLuvCode; 22.07.2017
comment
Ах, другие столбцы, которые вы не хотите eval, должны обрабатываться как test. Я изменю приведенный выше пример, чтобы показать, что я имею в виду. - person unutbu; 22.07.2017
comment
Я снова отредактировал свой вопрос, я стараюсь как можно точнее объяснить, чего я хочу :) @unutbu - person iLuvCode; 22.07.2017
comment
Обновите вывод df.head().to_dict('list'), чтобы отобразить столбцы lift и confidence, чтобы мы знали, с чего начинаем. Затем, учитывая опубликованные вами данные, покажите желаемый результат. - person unutbu; 22.07.2017
comment
на самом деле они не особенные, см. мой отредактированный вопрос, они оба поплавки. Я почти заработал, используя ваш пример (добавляя lift и confidence в функцию Melt.id_vars и setindex). Единственная часть, в которой я застрял, — это разделение столбца interests так же, как мы делали с users , поэтому повторяем строки в другой раз, но теперь с каждой строкой, содержащей один интерес, и фильтруем пустые списки interests. - person iLuvCode; 22.07.2017
comment
Плавление не кажется таким привлекательным теперь, когда я вижу, что столбцы interests и users должны обрабатываться по-разному. interests нужно взорвать дважды, а users только один раз. Поэтому я соответствующим образом изменил приведенный выше код. - person unutbu; 23.07.2017