Python 使用其他列的名称作为值创建DataFrame聚合列

Python 使用其他列的名称作为值创建DataFrame聚合列,python,pandas,pandas-apply,Python,Pandas,Pandas Apply,我试图在我的DataFrame中创建一个新列,它是聚合列名的列表。下面是一个示例DataFrame: In [1]: df = pd.DataFrame({'A':[1,2,3], 'B':[4,5,6], 'C':[7,8,9], 'D':[1,3,5], 'E':[5,3,6], 'F':[7,4,3]}) In [2]: df Out[2]:

我试图在我的
DataFrame
中创建一个新列,它是聚合列名的列表。下面是一个示例
DataFrame

In [1]: df = pd.DataFrame({'A':[1,2,3],
               'B':[4,5,6],
               'C':[7,8,9],
               'D':[1,3,5],
               'E':[5,3,6],
               'F':[7,4,3]})
In [2]: df
Out[2]:
   A  B  C  D  E  F
0  1  4  7  1  5  7
1  2  5  8  3  3  4
2  3  6  9  5  6  3
我想创建一个新列,其中包含满足特定条件的列名列表。假设我对value>3的列感兴趣——我希望输出如下所示:

In [3]: df
Out[3]:
   A  B  C  D  E  F  Flag
0  1  4  7  1  5  7  ['B', 'C', 'E', 'F']
1  2  5  8  3  3  4  ['B', 'C', 'F']
2  3  6  9  5  6  3  ['B', 'C', 'D', 'E']
目前,我正在使用
apply

df['Flag'] = df.apply(lambda row: [list(df)[i] for i, j in enumerate(row) if j > 3], axis = 1)
这可以完成任务,但感觉很笨拙,我想知道是否有更优雅的解决方案

谢谢

在此处使用:



一个选项是通过检查哪些值高于某个阈值来创建
布尔值的数据帧,并使用列名获取产品。最后使用
apply(list)
从结果字符串中获取列表:

df['Flag'] = df.gt(3).dot(df.columns).apply(list)

   A  B  C  D  E  F          Flag
0  1  4  7  1  5  7  [B, C, E, F]
1  2  5  8  3  3  4     [B, C, F]
2  3  6  9  5  6  3  [B, C, D, E]
另一种方式:

df['Flag'] = df.T.apply(lambda x: list(x[x>3].index))

我还是喜欢这里的循环

df['Flag']=[df.columns[x].tolist() for x in df.gt(3).values]
df
Out[968]: 
   A  B  C  D  E  F          Flag
0  1  4  7  1  5  7  [B, C, E, F]
1  2  5  8  3  3  4     [B, C, F]
2  3  6  9  5  6  3  [B, C, D, E]
编辑:为该问题的所有解决方案添加计时

我更喜欢不使用
apply

df['Flag'] = df.reset_index().melt(id_vars='index', value_name='val', var_name='col').query('val > 3').groupby('index')['col'].agg(list)


测试数据:

a = [
    [1,  4,  7,  1,  5,  7],
    [2,  5,  8,  3,  3,  4],
    [3,  6,  9,  5,  6,  3],
    ] * 10000

df = pd.DataFrame(a, columns = list('ABCDEF'))  
使用
%timeit
计时:

In [79]: %timeit (df>3).dot(df.columns).apply(list)
40.8 ms ± 1.66 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

In [80]: %timeit [df.columns[x].tolist() for x in df.gt(3).values]
1.23 s ± 10.3 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

In [81]: %timeit df.gt(3).dot(df.columns).apply(list)
37.6 ms ± 644 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

In [82]: %timeit df.T.apply(lambda x: list(x[x>3].index))
16.4 s ± 99.2 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

In [83]: %timeit df.stack().rename('val').reset_index(level=1).query('val > 3')
    ...: .groupby(level=0)['level_1'].agg(list)
4.05 s ± 15.6 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

In [84]: %timeit df.apply(lambda x: df.columns[np.argwhere(x>3).ravel()].values
    ...: , 1)
c:\program files\python37\lib\site-packages\numpy\core\fromnumeric.py:56: Future
Warning: Series.nonzero() is deprecated and will be removed in a future version.
Use Series.to_numpy().nonzero() instead
  return getattr(obj, method)(*args, **kwds)
12 s ± 45.2 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
最快的解决方案是使用
.dot
ravel()


我们也可以使用
@

df['Flag'] = ((df >3) @ df.columns).map(list)

你的答案可以用一个简短的解释,这样其他人可能会受益。时间安排非常有用!事实上,我自己也准备这么做,因为我的数据集是2mm+行,所以我在寻找最快的选项
apply
运行得非常慢
df.dot()
肯定是最有效的。这里没有考虑矩阵乘法。谢谢
a = [
    [1,  4,  7,  1,  5,  7],
    [2,  5,  8,  3,  3,  4],
    [3,  6,  9,  5,  6,  3],
    ] * 10000

df = pd.DataFrame(a, columns = list('ABCDEF'))  
In [79]: %timeit (df>3).dot(df.columns).apply(list)
40.8 ms ± 1.66 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

In [80]: %timeit [df.columns[x].tolist() for x in df.gt(3).values]
1.23 s ± 10.3 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

In [81]: %timeit df.gt(3).dot(df.columns).apply(list)
37.6 ms ± 644 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

In [82]: %timeit df.T.apply(lambda x: list(x[x>3].index))
16.4 s ± 99.2 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

In [83]: %timeit df.stack().rename('val').reset_index(level=1).query('val > 3')
    ...: .groupby(level=0)['level_1'].agg(list)
4.05 s ± 15.6 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

In [84]: %timeit df.apply(lambda x: df.columns[np.argwhere(x>3).ravel()].values
    ...: , 1)
c:\program files\python37\lib\site-packages\numpy\core\fromnumeric.py:56: Future
Warning: Series.nonzero() is deprecated and will be removed in a future version.
Use Series.to_numpy().nonzero() instead
  return getattr(obj, method)(*args, **kwds)
12 s ± 45.2 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
   df.apply(lambda x: df.columns[np.argwhere(x>3).ravel()].values, 1)
df['Flag'] = ((df >3) @ df.columns).map(list)