[英]More efficient way of pandas dataframe manipulation: filtering and melting
我有一个数据集,我需要从长到宽解析和操作。 每行代表一个人,并且有多个列代表测量实例(uk-biobank 格式):
import pandas as pd
# initialize data of lists.
data = {'id': ['1', '2', '3', '4'],
'3-0.0': [20, 21, 19, 18],
'3-1.0': [10, 11, 29, 12],
'3-2.0': [5, 6, 7, 8]}
# Create DataFrame
df = pd.DataFrame(data)
df.set_index('id')
3-0.0、3-1.0 和 3-2.0 是针对给定人的同一事件的三种不同度量。 我想要的是给定人员的多行和指示事件实例(0,1 或 2)的列,然后是关联值的列。
我的低效方法如下,我知道它可以做得更好。 我是 python 新手,所以寻找更有效的编码方法:
# parsing out each instance
i0 = df.filter(regex="\-0\.")
i1 = df.filter(regex="\-1\.")
i2 = df.filter(regex="\-2\.")
# set index as column and melt each df
i0.reset_index(inplace=True)
i0 = pd.melt(i0, id_vars = "index", ignore_index = True).dropna().drop(columns=['variable']).assign(instance = '0')
i1.reset_index(inplace=True)
i1 = pd.melt(i1, id_vars = "index", ignore_index = True).dropna().drop(columns=['variable']).assign(instance = '1')
i2.reset_index(inplace=True)
i2 = pd.melt(i2, id_vars = "index", ignore_index = True).dropna().drop(columns=['variable']).assign(instance = '2')
# concatenate back together
fin = pd.concat([i0,i1,i2])
data = {'id': ['1', '2', '3', '4'],
'3-0.0': [20, 21, 19, 18],
'3-1.0': [10, 11, 29, 12],
'3-2.0': [5, 6, 7, 8]}
# final dataset looks like this
id, measure, instance
1 20 0
1 10 1
1 5 2
2 21 0
2 11 1
2 6 2
3 19 0
3 29 1
3 7 2
4 18 0
4 12 1
4 8 2
如果您可以合并以下事实,则可以3-0.0','3-1.0', '3-2.0','4-0.0','4-1.0','4-2.0',...
鉴于:
id 3-0.0 3-1.0 3-2.0 4-0.0 4-1.0 4-2.0
0 1 20 10 5 10 5 20
1 2 21 11 6 11 6 21
2 3 19 29 7 29 7 19
3 4 18 12 8 12 8 18
正在做:
unique_people = df.filter(regex='\d-').columns.str.split('-').str[0].unique()
out = pd.wide_to_long(df, stubnames=unique_people, i='id', j='instance', sep='-', suffix='.*')
out = out.rename(int, level=1)
print(out.sort_index())
输出:
3 4
id instance
1 0 20 10
1 10 5
2 5 20
2 0 21 11
1 11 6
2 6 21
3 0 19 29
1 29 7
2 7 19
4 0 18 12
1 12 8
2 8 18
将列转换为 MultiIndex,然后使用重置索引取消堆叠
df.columns = df.columns.str.split('-').map(tuple)
df = df.unstack(level=1).reset_index([0, 1]).sort_index(level='id')
df.columns = ['major_instance', 'instance', 'measure']
输出
major_instance instance measure
id
1 3 0.0 20
1 3 1.0 10
1 3 2.0 5
2 3 0.0 21
2 3 1.0 11
2 3 2.0 6
3 3 0.0 19
3 3 1.0 29
3 3 2.0 7
4 3 0.0 18
4 3 1.0 12
4 3 2.0 8
使用str.split
by -
将id
转换为DataFrame.stack
索引的列名 - 然后将浮点数转换为整数, rename
3
列并创建 3 列 DataFrame:
df = df.set_index('id')
df.columns = df.columns.str.split('-', expand=True)
df = (df.stack()
.rename_axis(('id','instance'))
.rename(int, level=1)
.rename(columns={'3':'measure'})
.reset_index()[['id','measure','instance']]
)
print (df)
id measure instance
0 1 20 0
1 1 10 1
2 1 5 2
3 2 21 0
4 2 11 1
5 2 6 2
6 3 19 0
7 3 29 1
8 3 7 2
9 4 18 0
10 4 12 1
11 4 8 2
使用wide_to_long
并在-
之前指定3
和正则表达式r'\d+\.\d+'
的解决方案适用于匹配浮点数:
df = (pd.wide_to_long(df,
stubnames=['3'],
i='id',
j='instance',
sep='-',
suffix=r'\d+\.\d+')
.rename(int, level=1)
.sort_index()
.rename(columns={'3':'measure'})
.reset_index()[['id','measure','instance']])
print (df)
id measure instance
0 1 20 0
1 1 10 1
2 1 5 2
3 2 21 0
4 2 11 1
5 2 6 2
6 3 19 0
7 3 29 1
8 3 7 2
9 4 18 0
10 4 12 1
11 4 8 2
奖励:解决方案是从-
之前的部分列名中修改列:
df = df.set_index('id')
df.columns = df.columns.str.split('-', expand=True)
df = (df.stack()
.rename_axis(('id','instance'))
.rename(int, level=1)
.reset_index()
)
print (df)
id instance 3 4
0 1 0 20 10
1 1 1 10 5
2 1 2 5 20
3 2 0 21 11
4 2 1 11 6
5 2 2 6 21
6 3 0 19 29
7 3 1 29 7
8 3 2 7 19
9 4 0 18 12
10 4 1 12 8
11 4 2 8 18
df = (pd.wide_to_long(df,
stubnames=['3','4'],
i='id',
j='instance',
sep='-',
suffix=r'\d+\.\d+')
.rename(int, level=1)
.sort_index()
.reset_index())
print (df)
id instance 3 4
0 1 0 20 10
1 1 1 10 5
2 1 2 5 20
3 2 0 21 11
4 2 1 11 6
5 2 2 6 21
6 3 0 19 29
7 3 1 29 7
8 3 2 7 19
9 4 0 18 12
10 4 1 12 8
11 4 2 8 18
一种选择是使用pyjanitor的pivot_longer :
# pip install pyjanitor
import pandas as pd
import janitor
# `id` is a column, not an index
df.pivot_longer(index = 'id',
names_to = ('major_instance', 'instance'),
values_to = 'measure',
names_sep='-')
id major_instance instance measure
0 1 3 0.0 20
1 2 3 0.0 21
2 3 3 0.0 19
3 4 3 0.0 18
4 1 3 1.0 10
5 2 3 1.0 11
6 3 3 1.0 29
7 4 3 1.0 12
8 1 3 2.0 5
9 2 3 2.0 6
10 3 3 2.0 7
11 4 3 2.0 8
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.