pandas select 有条件的多列
pandas select multiple columns conditionally
假设我有一个数据框:
C1 V1 C2 V2 Cond
1 2 3 4 X
5 6 7 8 Y
9 10 11 12 X
报表应该return:if Cond == X, pick C1 and C2, else pick C2 and V2
。
输出数据帧类似于:
C V
1 2
7 8
9 10
** 编辑:再添加一个要求:列数可以更改但遵循某种命名模式。在这种情况下 select 所有列都包含“1”,否则包含“2”。我认为硬编码解决方案可能行不通。
drop
Cond
关注我从中选择的值
reshape
numpy 数组,这样我就可以用布尔值进行区分
- 索引第一个维度
np.arange(len(df))
,每行一次
- 用
df.Cond.ne('X').mul(1)
索引第二个维度。 0
等于 X
- 构建最终数据框
pd.DataFrame(
df.drop('Cond', 1).values.reshape(3, 2, 2)[
np.arange(len(df)),
df.Cond.ne('X').mul(1)
], df.index, ['C', 'V'])
C V
0 1 2
1 7 8
2 9 10
您可以尝试使用类似于 this post
中的方法
首先,定义几个函数:
def cond(row):
return row['Cond'] == 'X'
def helper(row, col_if, col_ifnot):
return row[col_if] if cond(row) else row[col_ifnot]
然后,假设您的数据框称为 df
,
df_new = pd.DataFrame(index=df.index)
for col in ['C', 'V']:
col_1 = col + '1'
col_2 = col + '2'
df_new[col] = df.apply(lambda row: helper(row, col_1, col_2), axis=1)
请记住,这种方法对于大型数据帧来说可能很慢,因为 apply
没有利用矢量化。但是,它甚至可以使用任意列名(只需将 ['C', 'V']
替换为您的实际列名)。
如果行的顺序不重要,您可以使用df.loc and df.append。
ndf1 = df.loc[df['Cond'] == 'X', ['C1','V1']]
ndf2 = df.loc[df['Cond'] == 'Y', ['C2','V2']]
ndf1.columns = ['C','V']
ndf2.columns = ['C','V']
result = ndf1.append(ndf2).reset_index(drop=True)
print(result)
C V
0 1 2
1 9 10
2 7 8
DataFrame.where()
的另一个选项:
df[['C1', 'V1']].where(df.Cond == "X", df[['C2', 'V2']].values)
# C1 V1
#0 1 2
#1 7 8
#2 9 10
我尝试使用 filter
and numpy.where
, for new column names use extract
创建更通用的解决方案:
#if necessary sort columns
df = df.sort_index(axis=1)
#filter df by 1 and 2
df1 = df.filter(like='1')
df2 = df.filter(like='2')
print (df1)
C1 V1
0 1 2
1 5 6
2 9 10
print (df2)
C2 V2
0 3 4
1 7 8
2 11 12
#np.where need same shape of mask as df1 and df2
mask = pd.concat([df.Cond == 'X']*len(df1.columns), axis=1)
print (mask)
Cond Cond
0 True True
1 False False
2 True True
cols = df1.columns.str.extract('([A-Za-z])', expand=False)
print (cols)
Index(['C', 'V'], dtype='object')
print (np.where(mask, df1,df2))
Index(['C', 'V'], dtype='object')
[[ 1 2]
[ 7 8]
[ 9 10]]
print (pd.DataFrame(np.where(mask, df1, df2), index=df.index, columns=cols))
C V
0 1 2
1 7 8
2 9 10
假设我有一个数据框:
C1 V1 C2 V2 Cond
1 2 3 4 X
5 6 7 8 Y
9 10 11 12 X
报表应该return:if Cond == X, pick C1 and C2, else pick C2 and V2
。
输出数据帧类似于:
C V
1 2
7 8
9 10
** 编辑:再添加一个要求:列数可以更改但遵循某种命名模式。在这种情况下 select 所有列都包含“1”,否则包含“2”。我认为硬编码解决方案可能行不通。
drop
Cond
关注我从中选择的值reshape
numpy 数组,这样我就可以用布尔值进行区分- 索引第一个维度
np.arange(len(df))
,每行一次 - 用
df.Cond.ne('X').mul(1)
索引第二个维度。0
等于X
- 构建最终数据框
pd.DataFrame(
df.drop('Cond', 1).values.reshape(3, 2, 2)[
np.arange(len(df)),
df.Cond.ne('X').mul(1)
], df.index, ['C', 'V'])
C V
0 1 2
1 7 8
2 9 10
您可以尝试使用类似于 this post
中的方法首先,定义几个函数:
def cond(row):
return row['Cond'] == 'X'
def helper(row, col_if, col_ifnot):
return row[col_if] if cond(row) else row[col_ifnot]
然后,假设您的数据框称为 df
,
df_new = pd.DataFrame(index=df.index)
for col in ['C', 'V']:
col_1 = col + '1'
col_2 = col + '2'
df_new[col] = df.apply(lambda row: helper(row, col_1, col_2), axis=1)
请记住,这种方法对于大型数据帧来说可能很慢,因为 apply
没有利用矢量化。但是,它甚至可以使用任意列名(只需将 ['C', 'V']
替换为您的实际列名)。
如果行的顺序不重要,您可以使用df.loc and df.append。
ndf1 = df.loc[df['Cond'] == 'X', ['C1','V1']]
ndf2 = df.loc[df['Cond'] == 'Y', ['C2','V2']]
ndf1.columns = ['C','V']
ndf2.columns = ['C','V']
result = ndf1.append(ndf2).reset_index(drop=True)
print(result)
C V
0 1 2
1 9 10
2 7 8
DataFrame.where()
的另一个选项:
df[['C1', 'V1']].where(df.Cond == "X", df[['C2', 'V2']].values)
# C1 V1
#0 1 2
#1 7 8
#2 9 10
我尝试使用 filter
and numpy.where
, for new column names use extract
创建更通用的解决方案:
#if necessary sort columns
df = df.sort_index(axis=1)
#filter df by 1 and 2
df1 = df.filter(like='1')
df2 = df.filter(like='2')
print (df1)
C1 V1
0 1 2
1 5 6
2 9 10
print (df2)
C2 V2
0 3 4
1 7 8
2 11 12
#np.where need same shape of mask as df1 and df2
mask = pd.concat([df.Cond == 'X']*len(df1.columns), axis=1)
print (mask)
Cond Cond
0 True True
1 False False
2 True True
cols = df1.columns.str.extract('([A-Za-z])', expand=False)
print (cols)
Index(['C', 'V'], dtype='object')
print (np.where(mask, df1,df2))
Index(['C', 'V'], dtype='object')
[[ 1 2]
[ 7 8]
[ 9 10]]
print (pd.DataFrame(np.where(mask, df1, df2), index=df.index, columns=cols))
C V
0 1 2
1 7 8
2 9 10