Python:按行中的非零值获取列名

Python:按行中的非零值获取列名,python,python-3.x,pandas,Python,Python 3.x,Pandas,假设我有10行3列。每行只有一个非零值,任何行的位置按列不同 如何迭代每一行,检查是否存在任何非零值,检查其列索引,并获取(存储在内存中)适当的列名 我尝试了几种使用熊猫图书馆的方法,但没有找到任何捷径 原始数据: index A B C D 11 0 3 0 0 136 0 0 0 1 186 0 0 184 0 258 0 0 15 0 455

假设我有10行3列。每行只有一个非零值,任何行的位置按列不同

如何迭代每一行,检查是否存在任何非零值,检查其列索引,并获取(存储在内存中)适当的列名

我尝试了几种使用熊猫图书馆的方法,但没有找到任何捷径

原始数据:

index  A  B    C  D                 
11     0  3    0  0     
136    0  0    0  1     
186    0  0  184  0     
258    0  0   15  0     
455    0  1    0  0     
628    0  0    1  0    
774    0  0    2  0     
829    0  0    1  0     
1004   0  0  113  0     
1008   0  0    1  0     
3个不同指标(136、455、1008)的一个预期输出示例:

当然,输出可以是列表列表之类的任何其他内容。但这个具体案例对我来说已经足够了

发现:

empty_list = []    
memory_var = [empty_list.append(row.sort_values().max()) for row in 
             df.itterows()]
print(memory_var)
这有助于我只列出每行的最高值。现在,我需要得到这些值的列名。使用“idxmax()”方法返回错误:

'numpy.float64' object has no attribute 'idxmax'
更新:

为我的案子找到了正确的解决方案。可通过以下方式提取特定柱:

row[:].sort_values().idxmax()

这就是你要找的吗

>>> a_df = pd.DataFrame({"a":[1,0,0,0], "b":[0,3,0,0], "c":[0,0,0,7], "d":[0,0,0,0]})
>>> a_df
   a  b  c  d
0  1  0  0  0
1  0  3  0  0
2  0  0  0  0
3  0  0  7  0

>>> a_df = a_df.replace(0, np.nan)
>>> a_df
     a    b    c   d
0  1.0  NaN  NaN NaN
1  NaN  3.0  NaN NaN
2  NaN  NaN  NaN NaN
3  NaN  NaN  7.0 NaN

>>> a_df.dropna(how="all", axis=1).columns.tolist()
['a', 'b', 'c']

如果要保留原始df,请执行以下操作:

>>> a_df.replace(0, np.nan).dropna(how="all", axis=1).columns.tolist()
['a', 'b', 'c']

>>> a_df
   a  b  c  d
0  1  0  0  0
1  0  3  0  0
2  0  0  0  0
3  0  0  7  0

另一种方法是在包含非零列名的原始数据帧末尾添加列:

df = pd.DataFrame({'x' : [ 0,0,9],'y' : [-1,0,0],'z' : [0,1.1,0]},index=['a','b','c'])
df["non_zero_columns"] = df.where(df == 0, 
                                  other=df.apply(lambda x: x.name), 
                                  axis=1).where(df != 0, 
                                                other="").apply(lambda row: ''.join(row.values), axis=1)
“df”现在是:

    x   y   z   non_zero_columns
a   0   -1  0.0 y
b   0   0   1.1 z
c   9   0   0.0 x

将一行分隔开来,两个where()调用将零设置为空字符串,将非零值设置为它们所在列的名称。这些值(空字符串和列名)在apply()中串接,以创建“非零列”列。

您可以使用DF的apply函数

迭代该行并检查该行的哪个索引处存在非零值。要获取列名,请使用df.columns

data = [[0, 0, 1], [0, 2, 0], [3, 0, 0], [0, 0, 4], [0, 5, 0], [6, 0, 0], [0, 0, 7], [0, 8, 0], [9, 0, 0], [0, 0, 10]]

df = pd.DataFrame(data, columns=["a", "b", "c"])

df["d"] = df.apply(lambda row: df.columns[[i for i in range(len(row)) if row[i] > 0][0]], axis=1)

   a  b   c  d
0  0  0   1  c
1  0  2   0  b
2  3  0   0  a
3  0  0   4  c
4  0  5   0  b
5  6  0   0  a
6  0  0   7  c
7  0  8   0  b
8  9  0   0  a
9  0  0  10  c
更新: 要获取非零值列的名称,请执行以下操作:

column_list = df["d"].tolist()
['c', 'b', 'a', 'c', 'b', 'a', 'c', 'b', 'a', 'c']
要仅获取特定位置的列名称,请执行以下操作:

df["d"].iloc[[1, 3, 5, 7]].tolist()
['b', 'c', 'a', 'b']

idxmax
非常适合于此。原始数据包括D列,所以我也使用了它:

from io import StringIO
import pandas as pd

data = '''index  A  B    C  D                 
11     0  3    0  0     
136    0  0    0  1     
186    0  0  184  0     
258    0  0   15  0     
455    0  1    0  0     
628    0  0    1  0    
774    0  0    2  0     
829    0  0    1  0     
1004   0  0  113  0     
1008   0  0    1  0   
'''
df = (pd.read_csv(StringIO(data), sep='\s\s+', engine='python')
        .set_index('index'))

那么您想要数据中所有非零值的行号和列名吗?不,我只想要列名。到列名称的导航基于选中的特定行中存在的任何非零值。我不确定我是否理解。所以我们在寻找那些不全是零的列?是的。就像在DataFrame对象中的行上迭代一样,检查是否有非零值,追加与行中的值位置对应的列名。这非常好而且非常有用。但是,这样做并避免使用.dropna()方法将更有帮助。原因是保留原始df的原样。为了精确回答我的问题,是否可以只对随机(或不随机)选择的一行进行强制转换?更新答案以保持原始df完整。如果要对df的子集执行操作,可以通过
a_df[:1]
进行切片,这将只保留前1行。感谢您的努力。然而,这并不像我想要的那么具体。预期的输出本身应该是,因此使用“.dropna()”和“.tolist()”不能帮助我获得正确的输出。我需要它特定于具体情况。假设我只想得到第6行中数字7的列名。如果我只想提取列名,作为一个新的列表对象,也是一样的。你能详细说明一下输入样本和预期输出吗?答案已经用输出更新了。如果解决了您的问题,请接受解决方案。已更新问题。对不起,这并不能解决我的问题。我需要它是针对具体情况的,这样数据操作应该尽可能少。这意味着我不想再创建一个列,并且列名的提取应该只基于选中行中的值。这一行更有用,但仍然不是我想要的。是否有一个选项可供lambda仅对特定行应用,并将结果列名转换为列表?我操纵了您的建议答案,并通过使用“.idxmax()”获得了预期的输出。因为这是与我的问题最接近的答案,我将其标记为“接受答案”。非常感谢你的努力。不幸的是,这对我帮助不大。我需要一些更具体的东西,将其存储在outter变量中(而不是作为一个新列存储在df本身中),如果可能的话,减少修饰性。这里的一些大脑使用与预期输出最接近的“idxmax()。然而,它不在那里。不用担心。您始终可以将该列拉至单独的变量,例如:
non\u zero\u columns=df[“non\u zero\u columns”]。根据需要,拉至dict()
至\u list
。坦白地说,我不知道“少打扮”是什么意思,所以我也没办法。
from io import StringIO
import pandas as pd

data = '''index  A  B    C  D                 
11     0  3    0  0     
136    0  0    0  1     
186    0  0  184  0     
258    0  0   15  0     
455    0  1    0  0     
628    0  0    1  0    
774    0  0    2  0     
829    0  0    1  0     
1004   0  0  113  0     
1008   0  0    1  0   
'''
df = (pd.read_csv(StringIO(data), sep='\s\s+', engine='python')
        .set_index('index'))
# apply idxmax and show result
df['col'] = df.apply(lambda x: x.idxmax(), axis=1)
print(df)

       A  B    C  D col
index                  
11     0  3    0  0   B
136    0  0    0  1   D
186    0  0  184  0   C
258    0  0   15  0   C
455    0  1    0  0   B
628    0  0    1  0   C
774    0  0    2  0   C
829    0  0    1  0   C
1004   0  0  113  0   C
1008   0  0    1  0   C