Впервые опубликовать вопрос от новичка кодера, открытого для предложений и улучшений.

Я пытаюсь создать новый столбец в кадре данных. Новый столбец для каждой строки должен быть заполнен следующим образом:

1) «Неизвестно», если все выбранные столбцы в этой строке содержат значение «Нет».

2) Значение, отличное от «Нет», если один из столбцов содержит такое значение.

В наборе данных, который я использую, будет только одно значение, отличное от «Нет», если оно есть в каждой строке, а имя столбца совпадает со значением ячейки.

Я знаю, что мог бы пройтись по каждой строке, чтобы найти значение, отличное от «Нет», в этих столбцах, и если он был найден, установить для него значение столбца (иначе установить как «Неизвестно»), но я чувствую, что упускаю что-то простое для сделать эту работу.

Я смотрел на выбор значения с помощью .loc / .iloc / .at и нескольких других методов, но я не чувствую, что приближаюсь.

import pandas as pd
import numpy as np

df = pd.DataFrame({'A': ['None', 'None', 'None', 'None'],
                   'B': ['None', 'B', 'None', 'None'],
                   'C': ['None', 'None', 'C', 'None'],
                   'D': ['None', 'None', 'None', 'D']})

values = ['B', 'C', 'D']

#In the code below, replace the string  'This should be non-None value (B, C or D)' with an expression
df['Letter'] = pd.np.where(df[values].eq(values).any(1, skipna=True), 
                           'This should be non-None value (B, C or D)', 'Unknown')
print(df)

   A     B     C     D     Letter
0  None  None  None  None  Unknown                                  
1  None  B     None  None  This should be non-None value (B, C or D)
2  None  None  C     None  This should be non-None value (B, C or D)
3  None  None  None  D     This should be non-None value (B, C or D)
2
valencia21 14 Сен 2018 в 12:01

2 ответа

Лучший ответ

Я считаю нужно:

df['Letter'] = df.ne('None').dot(df.columns).replace('', 'Unknown')
#if None are not strings
#df['Letter'] = df.notna().dot(df.columns).replace('', 'Unknown')
#oldier pandas versions
#df['Letter'] = df.notnull().dot(df.columns).replace('', 'Unknown')
print(df)
      A     B     C     D   Letter
0  None  None  None  None  Unknown
1  None     B  None  None        B
2  None  None     C  None        C
3  None  None  None     D        D

< Сильный > Объяснение :

Получите логическую маску без значений None путем сравнения по DataFrame.ne (!=) или DataFrame.notna:

print(df.ne('None'))
       A      B      C      D
0  False  False  False  False
1  False   True  False  False
2  False  False   True  False
3  False  False  False   True

Затем используйте DataFrame.dot с имена столбцов:

print(df.ne('None').dot(df.columns))
0     
1    B
2    C
3    D
dtype: object

И, наконец, замените отсутствующие значения на Series.replace :

print(df.ne('None').dot(df.columns).replace('', 'Unknown'))
0    Unknown
1          B
2          C
3          D
dtype: object

Другое решение:

df['Letter'] = df.replace('None', np.nan).ffill(axis=1).iloc[:, -1].fillna('Unknown')
print(df)
      A     B     C     D   Letter
0  None  None  None  None  Unknown
1  None     B  None  None        B
2  None  None     C  None        C
3  None  None  None     D        D

< Сильный > Объяснение :

Первые replace строки { {X1}} на пропущенные значения, если необходимо:

print (df.replace('None', np.nan))
    A    B    C    D
0 NaN  NaN  NaN  NaN
1 NaN    B  NaN  NaN
2 NaN  NaN    C  NaN
3 NaN  NaN  NaN    D

Вперед заполнить пропущенные значения:

print (df.replace('None', np.nan).ffill(axis=1))
     A    B    C    D
0  NaN  NaN  NaN  NaN
1  NaN    B    B    B
2  NaN  NaN    C    C
3  NaN  NaN  NaN    D

Выбрать последний столбец по позициям по DataFrame.iloc :

print (df.replace('None', np.nan).ffill(axis=1).iloc[:, -1])
0    NaN
1      B
2      C
3      D
Name: D, dtype: object

И, наконец, замените отсутствующие значения на Series.fillna :

print (df.replace('None', np.nan).ffill(axis=1).iloc[:, -1].fillna('Unknown'))
0    Unknown
1          B
2          C
3          D
Name: D, dtype: object
3
jezrael 14 Сен 2018 в 09:20

Пытаться:

df['new_col'] = df.apply(lambda x: [item for item in x if item!='None'][0] if len([item for item in x if item!='None'])>0 else 'Unknown',axis=1)

Но не ... другое решение намного лучше, я просто предоставлю это здесь, чтобы вы увидели, как это сделать с apply.

1
Frayal 14 Сен 2018 в 09:31