首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >基于旗帜的数据融合

基于旗帜的数据融合
EN

Stack Overflow用户
提问于 2020-12-27 05:56:16
回答 3查看 107关注 0票数 2

我有这样的数据:

代码语言:javascript
复制
pd.DataFrame({'time':['01-01-2020','02-01-2020','01-01-2020','02-01-2020'],'level':['q','q','r','r'],'a':[1,2,3,4],'b':[12,34,54,67],'c':[18,29,39,47],'a_1':[0.1,0.2,0.3,0.4],'a_2':[0,1,0,1],'b_1':[0.28,0.47,0.02,0.05],'b_2':[1,1,0,1],'c_1':[0.18,0.40,0.12,0.01],'c_2':[1,1,0,0]})
>>  time      level a   b   c   a_1 a_2  b_1   b_2  c_1   c_2
0   01-01-2020  q   1   12  18  0.1 0   0.28    1   0.18    1
1   02-01-2020  q   2   34  29  0.2 1   0.47    1   0.40    1
2   01-01-2020  r   3   54  39  0.3 0   0.02    0   0.12    0
3   02-01-2020  r   4   67  47  0.4 1   0.05    1   0.01    0

我希望用timelevel作为索引来融化数据,并将所有其他列作为行,其中的标志1对应于它们的前缀。例如:如果aa_1的值a_2为1时,则希望将它们的值列为valuesitems

代码语言:javascript
复制
>>   time   level column values items
0   01-01-2020  q   b   12  0.28
1   01-01-2020  q   c   18  0.18
2   02-01-2020  q   a   2   0.20
3   02-01-2020  q   b   34  0.47
4   02-01-2020  q   c   29  0.40
5   02-01-2020  r   a   4   0.40
6   02-01-2020  r   b   67  0.05

无论标志是什么,我都可以获得所有的值,然后对flags==1进行筛选。但是,在这种情况下,不知道如何“融化”/“解堆栈”。我尝试了很多方法,但都没有成功。请帮帮我。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2020-12-27 06:53:14

让我们来试试melt

代码语言:javascript
复制
i, c = ['time', 'level'], pd.Index(['a', 'b','c'])

# mask the values where flag=0
m = df[c + '_1'].mask(df[c + '_2'].eq(0).values)

# melt the dataframe & assign the items column
s = df[[*i, *c]].melt(i, var_name='columns')\
                .assign(items=m.values.T.reshape((-1, 1)))

# drop the nan values and sort the dataframe
s = s.dropna(subset=['items']).sort_values(i, ignore_index=True)

详细信息:

mask_1后缀结尾的列中的值,其中对应的标志列中的值等于0

代码语言:javascript
复制
   a_1   b_1   c_1
0  NaN  0.28  0.18
1  0.2  0.47  0.40
2  NaN   NaN   NaN
3  0.4  0.05   NaN

melt包含a, b, c列的dataframe,然后在reshape隐藏的值中指定一个新列items

代码语言:javascript
复制
          time level columns  value  items
0   01-01-2020     q       a      1    NaN
1   02-01-2020     q       a      2   0.20
2   01-01-2020     r       a      3    NaN
3   02-01-2020     r       a      4   0.40
4   01-01-2020     q       b     12   0.28
5   02-01-2020     q       b     34   0.47
6   01-01-2020     r       b     54    NaN
7   02-01-2020     r       b     67   0.05
8   01-01-2020     q       c     18   0.18
9   02-01-2020     q       c     29   0.40
10  01-01-2020     r       c     39    NaN
11  02-01-2020     r       c     47    NaN

最后,删除NaN值在itemssorttimelevel上的值,以获得的最终结果

代码语言:javascript
复制
         time level columns  value  items
0  01-01-2020     q       b     12   0.28
1  01-01-2020     q       c     18   0.18
2  02-01-2020     q       a      2   0.20
3  02-01-2020     q       b     34   0.47
4  02-01-2020     q       c     29   0.40
5  02-01-2020     r       a      4   0.40
6  02-01-2020     r       b     67   0.05
票数 3
EN

Stack Overflow用户

发布于 2020-12-27 06:23:21

也许有一个更优雅的方法,但这是可行的。提取每个列名(a,b,c)的数据,选择将标志设置为1的列,并将结果连接起来。

代码语言:javascript
复制
df.set_index(['time', 'level'], inplace=True)
parts = []
for name in 'a','b','c':
    d = df[[name, f'{name}_1', f'{name}_2']]\
         .rename(columns={name: 'values', f'{name}_1': 'items', f'{name}_2': 'flag'})
    d['column'] = name
    parts.append(d[d.flag == 1])
pd.concat(parts)[['column','values','items']].reset_index()
票数 1
EN

Stack Overflow用户

发布于 2020-12-27 08:05:20

第1步:重新排序列,以便数字出现在字母之前:

代码语言:javascript
复制
res = df.copy()
res.columns = ["_".join(entry.split("_")[::-1]) for entry in res]

Step2 :重新排序列(同样),如果列位于("a“、"b”、"c"),则"num“是前缀。

代码语言:javascript
复制
res.columns = [f"num_{letter}" if letter in ("a", "b", "c") 
               else letter 
               for letter in res]
res

time    level   num_a   num_b   num_c   1_a 2_a 1_b 2_b 1_c 2_c
0   01-01-2020  q   1   12  18  0.1 0   0.28    1   0.18    1
1   02-01-2020  q   2   34  29  0.2 1   0.47    1   0.40    1
2   01-01-2020  r   3   54  39  0.3 0   0.02    0   0.12    0
3   02-01-2020  r   4   67  47  0.4 1   0.05    1   0.01    0

第3步:使用熊猫宽至长重塑数据,过滤等于1的行,重命名列,最后重置索引:

代码语言:javascript
复制
(
    pd.wide_to_long(
        res,
        stubnames=["num", "1", "2"],
        i=["time", "level"],
        j="column",
        sep="_",
        suffix=".",
    )
     # this is where the filter for rows equal to 1 occur
    .query("`2`==1")
    .drop(columns="2")
    .set_axis(["values", "items"], axis="columns")
    .reset_index()
)


time    level   column  values  items
0   01-01-2020  q   b   12  0.28
1   01-01-2020  q   c   18  0.18
2   02-01-2020  q   a   2   0.20
3   02-01-2020  q   b   34  0.47
4   02-01-2020  q   c   29  0.40
5   02-01-2020  r   a   4   0.40
6   02-01-2020  r   b   67  0.05

这是另一种方式,但是重命名列的想法相同--使使用宽至长进行重组变得很容易。

代码语言:javascript
复制
result = df.rename(
    columns=lambda x: f"values_{x}"
    if x in ("a", "b", "c")
    else f"items_{x[0]}"
    if re.search(".1$", x)
    else f"equals1_{x[0]}"
    if re.search(".2$", x)
    else x
)


(
    pd.wide_to_long(
        result,
        stubnames=["values", "items", "equals1"],
        i=["time", "level"],
        j="column",
        sep="_",
        suffix=".",
    )
    .query("equals1==1")
    .iloc[:, :-1]
    .reset_index()
)

另一个选项是来自化脓者化脓者函数,使用.value占位符:

代码语言:javascript
复制
# pip install pyjanitor
import pandas as pd
import janitor

(df
.pivot_longer(index = ['time', 'level'], 
              names_to = ["column", ".value"], 
              names_pattern = r"(.)_?(.?)", 
              sort_by_appearance = True)
.query('`2` == 1')
.drop(columns = '2')
.rename(columns={'':'values', '1':'items'})
)

          time level column  values  items
1   01-01-2020     q      b      12   0.28
2   01-01-2020     q      c      18   0.18
3   02-01-2020     q      a       2   0.20
4   02-01-2020     q      b      34   0.47
5   02-01-2020     q      c      29   0.40
9   02-01-2020     r      a       4   0.40
10  02-01-2020     r      b      67   0.05
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65463249

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档