Explode dataframe column to multiple rows (TypeError: Cannot cast array data from dtype('int64') to dtype('int32'))
Explode dataframe column to multiple rows (TypeError: Cannot cast array data from dtype('int64') to dtype('int32'))
我会尝试用这些数据制作一个数据框:
test1 test2 test3
test [test1, test2] [testbelongsto1, testbelongst2]
像这样:
test1 test2 test3
test test1 testbelongsto1
test test2 testbelongsto2
我找到了这个问题的答案
看起来正是我需要的吗?
有很多问题可以回答我的问题..
然而,无论我尝试什么,我都遇到了这个错误:
TypeError: Cannot cast array data from dtype('int64') to dtype('int32') according to the rule 'safe'
使用此功能(参见 link):
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 转换为以其他格式保存它们的所有方法。
但是没有什么能解决问题...
请帮忙
更新:
几行的 'real' 数据集示例如下所示:
'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
`
所以我想要的是每个用户重复每个数据行(系列),每个用户的兴趣也是如此。
如果您相信您的数据不包含 malicious strings,那么您可以使用 eval
将字符串转换为 Python 对象。不过要非常小心——理论上,评估恶意字符串可以 运行 您计算机上的任意代码!
强调了 eval
的危险后,您可以使用 apply(pd.Series)
trick:
解析和重塑您的 DataFrame
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)
将列表"explode"分为列:
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
因为你也想 "explode" 集合,所以再次应用 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
列执行相同操作后,将两个 DataFrame 合并为一个:
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)
我会尝试用这些数据制作一个数据框:
test1 test2 test3
test [test1, test2] [testbelongsto1, testbelongst2]
像这样:
test1 test2 test3
test test1 testbelongsto1
test test2 testbelongsto2
我找到了这个问题的答案
然而,无论我尝试什么,我都遇到了这个错误:
TypeError: Cannot cast array data from dtype('int64') to dtype('int32') according to the rule 'safe'
使用此功能(参见 link):
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 转换为以其他格式保存它们的所有方法。 但是没有什么能解决问题...
请帮忙
更新: 几行的 'real' 数据集示例如下所示: '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
`
所以我想要的是每个用户重复每个数据行(系列),每个用户的兴趣也是如此。
如果您相信您的数据不包含 malicious strings,那么您可以使用 eval
将字符串转换为 Python 对象。不过要非常小心——理论上,评估恶意字符串可以 运行 您计算机上的任意代码!
强调了 eval
的危险后,您可以使用 apply(pd.Series)
trick:
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)
将列表"explode"分为列:
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
因为你也想 "explode" 集合,所以再次应用 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
列执行相同操作后,将两个 DataFrame 合并为一个:
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)