繁体   English   中英

更有效的 pandas 数据框操作方式:过滤和融合

[英]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

一种选择是使用pyjanitorpivot_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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM