创建以其他数据框上的值为条件的新数据框

Create new dataframe conditioned to values on other dataframe

我的数据框结构如下:

导入 pandas 作为 pd

import pandas as pd
data = {'date': ['2022-05-01 04:34:00', '2022-05-01 06:24:00', '2022-05-01 18:02:00', '2022-05-02 04:45:00'],
        'equipA_w1': ['NaN', 'NaN', 'NaN', 'NaN'],
        'equipB_w1': ['NaN', 'x', 'NaN', 'NaN'],
        'equipB_w2': ['NaN', 'NaN', 'y', 'z'],
        'equipB_w3': ['NaN', 'NaN', 'y', 'NaN'],
        'equipC_w2': ['NaN', 'x', 'x', 'NaN'],
        'equipA_e2': ['NaN', 'NaN', 'NaN', 'z'],
        'equipC_e1': ['y', 'NaN', 'NaN', 'NaN']
       }
 
df = pd.DataFrame(data)

我想创建一个新的数据框,最终会像这样:

有没有使用 pandas 的简单方法?

这将完成您的问题:

df = df.set_index('date').stack().to_frame().reset_index()
df.columns=['date','equip','value']
df = df[df.value != 'NaN'].reset_index(drop=True)
df.equip = df.equip.str.split('_').str[0]

完整测试代码:

import pandas as pd
data = {'date': ['2022-05-01 04:34:00', '2022-05-01 06:24:00', '2022-05-01 18:02:00', '2022-05-02 04:45:00'],
        'equipA_w1': ['NaN', 'NaN', 'NaN', 'NaN'],
        'equipB_w1': ['NaN', 'x', 'NaN', 'NaN'],
        'equipB_w2': ['NaN', 'NaN', 'y', 'z'],
        'equipB_w3': ['NaN', 'NaN', 'y', 'NaN'],
        'equipC_w2': ['NaN', 'x', 'x', 'NaN'],
        'equipA_e2': ['NaN', 'NaN', 'NaN', 'z'],
        'equipC_e1': ['y', 'NaN', 'NaN', 'NaN']
       }
 
df = pd.DataFrame(data)
print(df)

df = df.set_index('date').stack().to_frame().reset_index()
df.columns=['date','equip','value']
df = df[df.value != 'NaN'].reset_index(drop=True)
df.equip = df.equip.str.split('_').str[0]
print(df)

输入:

                  date equipA_w1 equipB_w1 equipB_w2 equipB_w3 equipC_w2 equipA_e2 equipC_e1
0  2022-05-01 04:34:00       NaN       NaN       NaN       NaN       NaN       NaN         y
1  2022-05-01 06:24:00       NaN         x       NaN       NaN         x       NaN       NaN
2  2022-05-01 18:02:00       NaN       NaN         y         y         x       NaN       NaN
3  2022-05-02 04:45:00       NaN       NaN         z       NaN       NaN         z       NaN

输出:

                  date   equip value
0  2022-05-01 04:34:00  equipC     y
1  2022-05-01 06:24:00  equipB     x
2  2022-05-01 06:24:00  equipC     x
3  2022-05-01 18:02:00  equipB     y
4  2022-05-01 18:02:00  equipB     y
5  2022-05-01 18:02:00  equipC     x
6  2022-05-02 04:45:00  equipB     z
7  2022-05-02 04:45:00  equipA     z

更新:

这里有一种方法可以用更少(但更长)的代码行来做到这一点:

df = df.set_index('date').stack().to_frame().reset_index().T.assign(
    new_index=['date','equip','value']).set_index('new_index').T
df = df[df.value != 'NaN'].reset_index(drop=True).transform(
    lambda col: col if col.name != 'equip' else col.str.split('_').str[0], axis=0)

这是实现它的一种方法

df2=df.melt( id_vars='date',var_name='equip', value_name='val')
df2['equip'] = df2['equip'].replace(r'_..','', regex=True)
df2.groupby(['date','equip','val']).last().reset_index()
df2.drop(df2[df2['val'] == 'NaN'].index, inplace=True)
df2
    date    equip   val
5   2022-05-01 06:24:00 equipB  x
10  2022-05-01 18:02:00 equipB  y
11  2022-05-02 04:45:00 equipB  z
14  2022-05-01 18:02:00 equipB  y
17  2022-05-01 06:24:00 equipC  x
18  2022-05-01 18:02:00 equipC  x
23  2022-05-02 04:45:00 equipA  z
24  2022-05-01 04:34:00 equipC  y

另一种方式:

(df.reset_index().melt(['index', 'date'],var_name = 'equip')
   .query('value!="NaN"')
   .assign(equip = lambda x:x.equip.str.replace('_.*', '', regex = True))
   .sort_values('index'))

    index                 date   equip value
24      0  2022-05-01 04:34:00  equipC     y
5       1  2022-05-01 06:24:00  equipB     x
17      1  2022-05-01 06:24:00  equipC     x
10      2  2022-05-01 18:02:00  equipB     y
14      2  2022-05-01 18:02:00  equipB     y
18      2  2022-05-01 18:02:00  equipC     x
11      3  2022-05-02 04:45:00  equipB     z
23      3  2022-05-02 04:45:00  equipA     z

或者简单地使用 janitor:

import janitor

(df.pivot_longer('date', names_to = 'equip', names_pattern = '(equip.)', sort_by_appearance = True)
  .query('value != "NaN"')
  .reset_index(drop  =True))

                  date   equip value
0  2022-05-01 04:34:00  equipC     y
1  2022-05-01 06:24:00  equipB     x
2  2022-05-01 06:24:00  equipC     x
3  2022-05-01 18:02:00  equipB     y
4  2022-05-01 18:02:00  equipB     y
5  2022-05-01 18:02:00  equipC     x
6  2022-05-02 04:45:00  equipB     z
7  2022-05-02 04:45:00  equipA     z

其中 names_pattern 是捕获列输入内容的正则表达式。在这种情况下,表达式 (equip[A-Z]+) 甚至 ([^_]+) 等都可以工作