创建以其他数据框上的值为条件的新数据框
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]+)
甚至 ([^_]+)
等都可以工作
我的数据框结构如下:
导入 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]+)
甚至 ([^_]+)
等都可以工作