如何在 pandas 数据框中展平数组
how to flatten array in pandas dataframe
假设我有一个 pandas 数据框,例如
df_p = pd.DataFrame(
{'name_array':
[[20130101, 320903902, 239032902],
[20130101, 3253453, 239032902],
[65756, 4342452, 32425432523]],
'name': ['a', 'a', 'c']} )
我想提取每行包含展平数组的系列,同时保留顺序
预期结果是 pandas.core.series.Series
这个问题不是重复的,因为我的预期输出是 pandas 系列,而不是数据框。
这是我想出的解决办法。不知道有没有更有效的方法。
df_p = pd.DataFrame(
{'name_array':
[[20130101, 320903902, 239032902],
[20130101, 3253453, 239032902],
[65756, 4342452, 32425432523]],
'name': ['a', 'a', 'c']} )
data = pd.DataFrame( {'column':np.concatenate(df_p['name_array'].values)} )['column']
输出:
[0 20130101
1 320903902
2 239032902
3 20130101
4 3253453
5 239032902
6 65756
7 4342452
8 32425432523
Name: column, dtype: int64]
您可以使用 pd.melt
:
pd.melt(df_p.name_array.apply(pd.Series).reset_index(),
id_vars=['index'],
value_name='name_array') \
.drop('variable', axis=1) \
.sort_values('index')
输出:
index name_array
0 20130101
0 320903902
0 239032902
1 20130101
1 3253453
1 239032902
2 65756
2 4342452
2 32425432523
使用 melt
的解决方案比他们在答案 中分享的 OP 的原始方法慢,尤其是在我对该答案的评论加速之后。
我创建了一个更大的数据框来测试:
df = pd.DataFrame({'name_array': np.random.rand(1000, 3).tolist()})
并在此数据帧上使用 melt
对两个解决方案进行计时,产量:
In [16]: %timeit pd.melt(df.name_array.apply(pd.Series).reset_index(), id_vars=['index'],value_name='name_array').drop('variable', axis=1).sort_values('index')
173 ms ± 5.68 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
In [17]: %timeit df['name_array'].apply(lambda x: pd.Series([i for i in x])).melt().drop('variable', axis=1)['value']
175 ms ± 4.86 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
我在评论中建议的具有加速的 OP 方法:
In [18]: %timeit pd.Series(np.concatenate(df['name_array']))
18 ms ± 887 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
最后,提供的最快解决方案 但经过修改以提供系列而不是数据帧输出:
In [14]: from itertools import chain
In [15]: %timeit pd.Series(list(chain.from_iterable(df['name_array'])))
402 µs ± 4.68 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
最后一种方法比 melt()
快 3 个数量级,比 np.concatenate()
快 2 个数量级。
您可以展平列的列表,然后通过这种方式创建一系列:
pd.Series([element for row in df_p.name_array for element in row])
假设我有一个 pandas 数据框,例如
df_p = pd.DataFrame(
{'name_array':
[[20130101, 320903902, 239032902],
[20130101, 3253453, 239032902],
[65756, 4342452, 32425432523]],
'name': ['a', 'a', 'c']} )
我想提取每行包含展平数组的系列,同时保留顺序
预期结果是 pandas.core.series.Series
这个问题不是重复的,因为我的预期输出是 pandas 系列,而不是数据框。
这是我想出的解决办法。不知道有没有更有效的方法。
df_p = pd.DataFrame(
{'name_array':
[[20130101, 320903902, 239032902],
[20130101, 3253453, 239032902],
[65756, 4342452, 32425432523]],
'name': ['a', 'a', 'c']} )
data = pd.DataFrame( {'column':np.concatenate(df_p['name_array'].values)} )['column']
输出:
[0 20130101
1 320903902
2 239032902
3 20130101
4 3253453
5 239032902
6 65756
7 4342452
8 32425432523
Name: column, dtype: int64]
您可以使用 pd.melt
:
pd.melt(df_p.name_array.apply(pd.Series).reset_index(),
id_vars=['index'],
value_name='name_array') \
.drop('variable', axis=1) \
.sort_values('index')
输出:
index name_array
0 20130101
0 320903902
0 239032902
1 20130101
1 3253453
1 239032902
2 65756
2 4342452
2 32425432523
使用 melt
的解决方案比他们在答案
我创建了一个更大的数据框来测试:
df = pd.DataFrame({'name_array': np.random.rand(1000, 3).tolist()})
并在此数据帧上使用 melt
对两个解决方案进行计时,产量:
In [16]: %timeit pd.melt(df.name_array.apply(pd.Series).reset_index(), id_vars=['index'],value_name='name_array').drop('variable', axis=1).sort_values('index')
173 ms ± 5.68 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
In [17]: %timeit df['name_array'].apply(lambda x: pd.Series([i for i in x])).melt().drop('variable', axis=1)['value']
175 ms ± 4.86 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
我在评论中建议的具有加速的 OP 方法:
In [18]: %timeit pd.Series(np.concatenate(df['name_array']))
18 ms ± 887 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
最后,提供的最快解决方案
In [14]: from itertools import chain
In [15]: %timeit pd.Series(list(chain.from_iterable(df['name_array'])))
402 µs ± 4.68 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
最后一种方法比 melt()
快 3 个数量级,比 np.concatenate()
快 2 个数量级。
您可以展平列的列表,然后通过这种方式创建一系列:
pd.Series([element for row in df_p.name_array for element in row])