Python 新列的条件生成
我正在尝试基于预先存在的列上的条件逻辑创建一个新列。我知道可能有更有效的方法来实现这一点,但我有一些条件需要包括在内。这只是第一步 总体范围是创建从Python 新列的条件生成,python,pandas,conditional-statements,Python,Pandas,Conditional Statements,我正在尝试基于预先存在的列上的条件逻辑创建一个新列。我知道可能有更有效的方法来实现这一点,但我有一些条件需要包括在内。这只是第一步 总体范围是创建从1和2映射的两个新列。它们被引用到对象列,因为我可以为每个时间点创建多行 Object2和Value确定如何映射新列。因此,如果Value==X,我想匹配Object列,将该时间点对应的1和2返回到一个新列。如果值为==Y,则应发生相同的过程。如果值为==Z,我想插入0,0。其他所有内容都应该是NaN df = pd.DataFrame({
1
和2
映射的两个新列。它们被引用到对象
列,因为我可以为每个时间点创建多行
Object2
和Value
确定如何映射新列。因此,如果Value==X
,我想匹配Object
列,将该时间点对应的1
和2
返回到一个新列。如果值为==Y
,则应发生相同的过程。如果值为==Z
,我想插入0,0
。其他所有内容都应该是NaN
df = pd.DataFrame({
'Time' : ['2019-08-02 09:50:10.1','2019-08-02 09:50:10.1','2019-08-02 09:50:10.2','2019-08-02 09:50:10.3','2019-08-02 09:50:10.3','2019-08-02 09:50:10.4','2019-08-02 09:50:10.5','2019-08-02 09:50:10.6','2019-08-02 09:50:10.6'],
'Object' : ['B','A','A','A','C','C','C','B','B'],
'1' : [1,3,5,7,9,11,13,15,17],
'2' : [0,1,4,6,8,10,12,14,16],
'Object2' : ['A','A',np.nan,'C','C','C','C','B','A'],
'Value' : ['X','X',np.nan,'Y','Y','Y','Y','Z',np.nan],
})
def map_12(df):
for i in df['Value']:
if i == 'X':
df['A1'] = df['1']
df['A2'] = df['2']
elif i == 'Y':
df['A1'] = df['1']
df['A2'] = df['2']
elif i == 'Z':
df['A1'] = 0
df['A2'] = 0
else:
df['A1'] = np.nan
df['A2'] = np.nan
return df
预期产出:
Time Object 1 2 Object2 Value A1 A2
0 2019-08-02 09:50:10.1 A 1 0 A X 1.0 0.0 # Match A-A at this time point, so output is 1,0
1 2019-08-02 09:50:10.1 B 3 1 A X 1.0 0.0 # Still at same time point so use 1,0
2 2019-08-02 09:50:10.2 A 5 4 NaN NaN NaN NaN # No Value so NaN
3 2019-08-02 09:50:10.3 C 7 6 C Y 7.0 6.0 # Match C-C at this time point, so output is 7,6
4 2019-08-02 09:50:10.3 A 9 8 C Y 7.0 6.0 # Still at same time point so use 7,6
5 2019-08-02 09:50:10.4 C 11 10 C Y 11.0 10.0 # Match C-C at this time point, so output is 11,10
6 2019-08-02 09:50:10.5 C 13 12 C Y 13.0 12.0 # Match C-C at this time point, so output is 13,12
7 2019-08-02 09:50:10.6 B 15 14 B Z 0.0 0.0 # Z so 0,0
8 2019-08-02 09:50:10.6 B 17 16 A NaN NaN NaN # No Value so NaN
Time Object 1 2 Object2 Value A1 A2
0 2019-08-02 09:50:10.1 B 1 0 A X 3.0 1.0 # Match A-A at this time point, so output is 3,1
1 2019-08-02 09:50:10.1 A 3 1 A X 3.0 1.0 # Still at same time point so use 3,1
2 2019-08-02 09:50:10.2 A 5 4 NaN NaN NaN NaN # No Value so NaN
3 2019-08-02 09:50:10.3 A 7 6 C Y 9.0 8.0 # Match C-C at this time point, so output is 9,8
4 2019-08-02 09:50:10.3 C 9 8 C Y 9.0 8.0 # Still at same time point so use 9,8
5 2019-08-02 09:50:10.4 C 11 10 C Y 11.0 10.0 # Match C-C at this time point, so output is 11,10
6 2019-08-02 09:50:10.5 C 13 12 C Y 13.0 12.0 # Match C-C at this time point, so output is 13,12
7 2019-08-02 09:50:10.6 B 15 14 B Z 0.0 0.0 # Z so 0,0
8 2019-08-02 09:50:10.6 B 17 16 A NaN NaN NaN # No Value so NaN
新样本df:
df = pd.DataFrame({
'Time' : ['2019-08-02 09:50:10.1','2019-08-02 09:50:10.1','2019-08-02 09:50:10.2','2019-08-02 09:50:10.3','2019-08-02 09:50:10.3','2019-08-02 09:50:10.4','2019-08-02 09:50:10.5','2019-08-02 09:50:10.6','2019-08-02 09:50:10.6'],
'Object' : ['B','A','A','A','C','C','C','B','B'],
'1' : [1,3,5,7,9,11,13,15,17],
'2' : [0,1,4,6,8,10,12,14,16],
'Object2' : ['A','A',np.nan,'C','C','C','C','B','A'],
'Value' : ['X','X',np.nan,'Y','Y','Y','Y','Z',np.nan],
})
预期产出:
Time Object 1 2 Object2 Value A1 A2
0 2019-08-02 09:50:10.1 A 1 0 A X 1.0 0.0 # Match A-A at this time point, so output is 1,0
1 2019-08-02 09:50:10.1 B 3 1 A X 1.0 0.0 # Still at same time point so use 1,0
2 2019-08-02 09:50:10.2 A 5 4 NaN NaN NaN NaN # No Value so NaN
3 2019-08-02 09:50:10.3 C 7 6 C Y 7.0 6.0 # Match C-C at this time point, so output is 7,6
4 2019-08-02 09:50:10.3 A 9 8 C Y 7.0 6.0 # Still at same time point so use 7,6
5 2019-08-02 09:50:10.4 C 11 10 C Y 11.0 10.0 # Match C-C at this time point, so output is 11,10
6 2019-08-02 09:50:10.5 C 13 12 C Y 13.0 12.0 # Match C-C at this time point, so output is 13,12
7 2019-08-02 09:50:10.6 B 15 14 B Z 0.0 0.0 # Z so 0,0
8 2019-08-02 09:50:10.6 B 17 16 A NaN NaN NaN # No Value so NaN
Time Object 1 2 Object2 Value A1 A2
0 2019-08-02 09:50:10.1 B 1 0 A X 3.0 1.0 # Match A-A at this time point, so output is 3,1
1 2019-08-02 09:50:10.1 A 3 1 A X 3.0 1.0 # Still at same time point so use 3,1
2 2019-08-02 09:50:10.2 A 5 4 NaN NaN NaN NaN # No Value so NaN
3 2019-08-02 09:50:10.3 A 7 6 C Y 9.0 8.0 # Match C-C at this time point, so output is 9,8
4 2019-08-02 09:50:10.3 C 9 8 C Y 9.0 8.0 # Still at same time point so use 9,8
5 2019-08-02 09:50:10.4 C 11 10 C Y 11.0 10.0 # Match C-C at this time point, so output is 11,10
6 2019-08-02 09:50:10.5 C 13 12 C Y 13.0 12.0 # Match C-C at this time point, so output is 13,12
7 2019-08-02 09:50:10.6 B 15 14 B Z 0.0 0.0 # Z so 0,0
8 2019-08-02 09:50:10.6 B 17 16 A NaN NaN NaN # No Value so NaN
看看
我不得不对您的数据帧进行一些调整,因为它与您问题中的预期结果不匹配
df = pd.DataFrame(
{
"Time": [
"2019-08-02 09:50:10.1",
"2019-08-02 09:50:10.1",
"2019-08-02 09:50:10.2",
"2019-08-02 09:50:10.3",
"2019-08-02 09:50:10.3",
"2019-08-02 09:50:10.4",
"2019-08-02 09:50:10.5",
"2019-08-02 09:50:10.6",
"2019-08-02 09:50:10.6",
],
"Object": ["A", "B", "A", "C", "A", "C", "C", "B", "B"],
"1": [1, 1, 5, 7, 9, 11, 13, 15, 17],
"2": [0, 1, 4, 6, 8, 10, 12, 14, 16],
"Object2": ["A", "A", np.nan, "C", "C", "C", "C", "B", "A"],
"Value": ["X", "X", np.nan, "Y", "Y", "Y", "Y", "Z", np.nan],
}
)
这是一个矢量化的解决方案,应该在大数据上运行良好
第一步是确保数据帧按时间排序
df = df.sort_values("Time")
复制第1列和第2列
df["A1"] = df["1"]
df["A2"] = df["2"]
将使用索引值获取每个时间组的第一行
df = df.reset_index()
我对列表/isin解决方案不太满意。好奇是否有人知道一种不那么老套的方法
li = df.groupby("Time").index.first().tolist()
print(li)
[0, 2, 3, 5, 6, 7]
print(df)
index Time Object 1 2 Object2 Value A1 A2
0 0 2019-08-02 09:50:10.1 A 1 0 A X 1 0
1 1 2019-08-02 09:50:10.1 B 1 1 A X 1 1
2 2 2019-08-02 09:50:10.2 A 5 4 NaN NaN 5 4
3 3 2019-08-02 09:50:10.3 C 7 6 C Y 7 6
4 4 2019-08-02 09:50:10.3 A 9 8 C Y 9 8
5 5 2019-08-02 09:50:10.4 C 11 10 C Y 11 10
6 6 2019-08-02 09:50:10.5 C 13 12 C Y 13 12
7 7 2019-08-02 09:50:10.6 B 15 14 B Z 15 14
8 8 2019-08-02 09:50:10.6 B 17 16 A NaN 17 16
过滤数据帧以获取除列表中的行以外的所有行,然后将它们设置为np.NaN
df.loc[~df.index.isin(li), ["A1", "A2"]] = np.NaN
df.loc[df["Value"] == "Z", ["A1", "A2"]] = 0
df.loc[df["Value"].isnull(), ["A1", "A2"]] = np.NaN
向前填充第一行值
df[["A1", "A2"]] = df[["A1", "A2"]].ffill(axis=0)
将z设置为0,将np.NaN设置为np.NaN
df.loc[~df.index.isin(li), ["A1", "A2"]] = np.NaN
df.loc[df["Value"] == "Z", ["A1", "A2"]] = 0
df.loc[df["Value"].isnull(), ["A1", "A2"]] = np.NaN
删除索引列
df = df.drop("index", axis=1)
print(df)
Time Object 1 2 Object2 Value A1 A2
0 2019-08-02 09:50:10.1 A 1 0 A X 1.0 0.0
1 2019-08-02 09:50:10.1 B 1 1 A X 1.0 0.0
2 2019-08-02 09:50:10.2 A 5 4 NaN NaN NaN NaN
3 2019-08-02 09:50:10.3 C 7 6 C Y 7.0 6.0
4 2019-08-02 09:50:10.3 A 9 8 C Y 7.0 6.0
5 2019-08-02 09:50:10.4 C 11 10 C Y 11.0 10.0
6 2019-08-02 09:50:10.5 C 13 12 C Y 13.0 12.0
7 2019-08-02 09:50:10.6 B 15 14 B Z 0.0 0.0
8 2019-08-02 09:50:10.6 B 17 16 A NaN NaN NaN
使用+创建类似于df[['1','2']]
但仅适用于匹配为True
的行,其余为NaN
。
然后使用时间点分组,并用现有值填充每组缺失的数据其中Object
和Object2
(匹配==True
)重合。用于在df['Value']
为NaN
的位置分解值。最后,当Z
位于Value
列中时,使用[DataFrame.mask
]设置0
#matches
matches=df.Object.eq(df.Object2)
#Creating conditions
condition_z=df['Value']=='Z'
not_null=df['Value'].notnull()
#Creating DataFrame to fill
df12=( df[['1','2']].where(matches)
.groupby(df['Time'],sort=False)
.apply(lambda x: x.ffill().bfill()) )
#fill 0 on Value is Z and discarting NaN
df[['A1','A2']] =df12.where(not_null).mask(condition_z,0)
print(df)
输出
Time Object 1 2 Object2 Value A1 A2
0 2019-08-02 09:50:10.1 B 1 0 A X 3.0 1.0
1 2019-08-02 09:50:10.1 A 3 1 A X 3.0 1.0
2 2019-08-02 09:50:10.2 A 5 4 NaN NaN NaN NaN
3 2019-08-02 09:50:10.3 A 7 6 C Y 9.0 8.0
4 2019-08-02 09:50:10.3 C 9 8 C Y 9.0 8.0
5 2019-08-02 09:50:10.4 C 11 10 C Y 11.0 10.0
6 2019-08-02 09:50:10.5 C 13 12 C Y 13.0 12.0
7 2019-08-02 09:50:10.6 B 15 14 B Z 0.0 0.0
8 2019-08-02 09:50:10.6 B 17 16 A NaN NaN NaN
我们还可以使用:
如果只有少数条件用于按条件赋值:
m1 = df['Value'].isin(['X','Y'])
m2 = df['Value'] == 'Z'
df[['A1','A2']] = df.loc[m1, ['1','2']]
df.loc[m2, ['A1','A2']] = 0
print(df)
Time Object 1 2 Object2 Value A1 A2
0 2019-08-02 09:50:10.1 A 1 0 A X 1.0 0.0
1 2019-08-02 09:50:10.1 B 1 1 A X 1.0 1.0
2 2019-08-02 09:50:10.2 A 5 4 NaN NaN NaN NaN
3 2019-08-02 09:50:10.3 C 7 6 C Y 7.0 6.0
4 2019-08-02 09:50:10.3 A 9 8 C Y 9.0 8.0
5 2019-08-02 09:50:10.4 C 11 10 NaN NaN NaN NaN
6 2019-08-02 09:50:10.5 C 13 12 B NaN NaN NaN
7 2019-08-02 09:50:10.6 B 15 14 B Z 0.0 0.0
8 2019-08-02 09:50:10.6 B 17 16 B NaN NaN NaN
另一个解决方案是使用和播放遮罩:
m1 = df['Value'].isin(['X','Y'])
m2 = df['Value'] == 'Z'
masks = [m1.values[:, None], m2.values[:, None]]
values = [df[['1','2']].values, 0]
df[['A1','A2']] = pd.DataFrame(np.select(masks,values, default=np.nan), index=df.index)
print(df)
Time Object 1 2 Object2 Value A1 A2
0 2019-08-02 09:50:10.1 A 1 0 A X 1.0 0.0
1 2019-08-02 09:50:10.1 B 1 1 A X 1.0 1.0
2 2019-08-02 09:50:10.2 A 5 4 NaN NaN NaN NaN
3 2019-08-02 09:50:10.3 C 7 6 C Y 7.0 6.0
4 2019-08-02 09:50:10.3 A 9 8 C Y 9.0 8.0
5 2019-08-02 09:50:10.4 C 11 10 NaN NaN NaN NaN
6 2019-08-02 09:50:10.5 C 13 12 B NaN NaN NaN
7 2019-08-02 09:50:10.6 B 15 14 B Z 0.0 0.0
8 2019-08-02 09:50:10.6 B 17 16 B NaN NaN NaN
你有什么问题?这是最接近的,而不是
df['A1']=df['1']
df['A1']=1谢谢@run out。我认为我们需要包含对对象列的引用。仅当先列出参考值时,此选项才有效。我将添加一个新的示例df以显示错误。在有多个条目的情况下,我如何确定应该使用哪个“参考值”?谢谢@jezrael,这比这个稍微复杂一点。我已经对我的预期输出添加了评论,并添加了一个新的示例df来突出这一点。感谢@ansev在这里的努力,但我的预期输出稍微复杂一些。我已经添加了强调逻辑的注释。感谢您澄清。更新了我的解决方案的所有方法。请检查:)谢谢ansev,但我的预期输出有点不同。我需要为每个时间点匹配Object
列,并填充到下一个时间点。这有意义吗。我的预期输出已经为每一行添加了注释。请注意,Object和Object2之间的等价性是按时间分组的,并使用transform(“any”)进行扩展。请查看我的预期输出。索引1和索引4位于同一时间点,因此我仍然希望使用前几行中匹配的数字。