【问题标题】:pandas get unique value row by rows熊猫逐行获取唯一值
【发布时间】:2019-07-12 09:38:35
【问题描述】:

我喜欢根据跨多列的行逐行获取唯一值,

数据示例:

col_a|col_b|col_c|col_d
-----------------------
apple|null|apple|null
bob|bob|null|bob
chris|chirs|null|null

预期输出:

new_col
-------
apple
bob
chris

【问题讨论】:

  • 您的意思是“唯一”还是“非空”值?
  • 唯一值和非空值
  • df.assign(new=df.mode(axis=1)) ??你只想要每一行的模式吗?
  • df.assign(new=df.mode(axis=1)) 好像不行,逐行查找唯一名称

标签: pandas unique


【解决方案1】:

你可以试试这个:

data['new_col'] = data.stack().groupby(level=0).apply(lambda x: x.unique().tolist())

示例 1:

   col_a col_b  col_c col_d
0  apple   NaN  apple   NaN
1    bob   bob    NaN   bob

输出:

   col_a col_b  col_c col_d  new_col
0  apple   NaN  apple   NaN  [apple]
1    bob   bob    NaN   bob    [bob]

示例 2:

   col_a col_b  col_c col_d
0  apple   bob  apple   NaN
1    bob   bob    NaN   bob

输出:

  col_a col_b  col_c col_d         new_col
0  apple   bob  apple   NaN  [apple, bob]
1    bob   bob    NaN   bob         [bob]

示例 3:

   col_a  col_b  col_c col_d
0  apple    NaN  apple   NaN
1    bob    bob    NaN   bob
2  chris  chris    NaN   NaN

输出:

   col_a  col_b  col_c col_d  new_col
0  apple    NaN  apple   NaN  [apple]
1    bob    bob    NaN   bob    [bob]
2  chris  chris    NaN   NaN  [chris]

【讨论】:

  • 我认为你应该解释一下它的作用
  • 这里,dataframe.stack() 基本上将数据帧从列堆叠到索引(多级索引),然后我们按特定级别(在我们的例子中,级别=0)进行分组,最后应用 lambda 函数到分组数据。在这里,我们也可以使用lambda x:list(set(x))代替lambda x: x.unique().tolist()
  • 感谢您的解释,但那不适合我。目的是改善您的答案,该答案缺乏对其实际作用的解释。 :)
【解决方案2】:

另一种想法:

data = pd.DataFrame(
    {
        "col_a": ["apple", "bob"],
        "col_b": [np.nan, "bob"],
        "col_c": ["apple", np.nan],
        "col_d": [np.nan, "bob"],
    }
) 
for i, row in data.iterrows():
    print(row.T[row.T.notnull()].unique())

【讨论】:

  • 据我所知,您应该尽可能避免使用.iterrows()
  • @ImCoins 的答案更快(也更惯用)。
【解决方案3】:

我认为一个简单的应用就可以了。

lambda row:row[~row.isna()].unique().tolist(), axis=1

这一行意味着对于每一行,您将只保留不等于NaN 的值,从中获取唯一值,转换为列表。 axis=1 可能是您最初未能找到的。 :)

import pandas as pd
import numpy as np

df = pd.DataFrame({
    'a' : [1, 2, 3],
    'b' : [np.nan, 5, 6]
})

df['unique'] = df.apply(lambda row:row[~row.isna()].unique().tolist(), axis=1) 
print(df)
#   a    b      unique
#0  1  NaN       [1.0]
#1  2  5.0  [2.0, 5.0]
#2  3  6.0  [3.0, 6.0]

【讨论】:

    【解决方案4】:

    这只是上述答案的另一种变体。虽然我没有彻底测试过第一个答案,但是,它似乎在这个例子中有效。 这个想法是逐行使用apply函数(因此axis = 1)并获取列表中每一行的唯一值。

    test = pd.DataFrame({'col1':['apple','bob'],
                         'col2':[np.nan,'bob'],
                         'col3':['apple',np.nan],
                        'col4':[np.nan,'bob']})
    test['new_col'] = test.apply(lambda row: row.dropna().unique(),axis=1)
    

    输出

    col1    col2    col3    col4    new_col
    apple   NaN    apple     NaN    [apple]
    bob     bob    NaN       bob    [bob]
    

    【讨论】:

    • 感谢 :) 澄清我编辑了答案。
    • 另一件事,每当我使用 apply 时,我喜欢命名我收到的输入以告诉读者我正在迭代... row/col(从 DataFrame 应用),或者一个值(从系列应用)。我认为它比基本的x lambda 更清楚——你可以不同意,但我认为我会为此付出 2 美分。 :)
    • 我 100% 同意你的观点,这是一个很好的做法。我再次根据您的建议进行了编辑
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-05-20
    • 2015-01-14
    • 2016-07-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-02
    • 1970-01-01
    相关资源
    最近更新 更多