Получить первое ненулевое значение в строке - PullRequest
0 голосов
/ 24 апреля 2018

У меня есть образец данных, как показано ниже. Для каждой строки я хочу сначала проверить c1, если она не равна нулю, то проверить c2. Таким образом, найдите первый столбец notnull и сохраните это значение в результате столбца.

ID  c1  c2  c3  c4  result
1   a   b           a
2       cc  dd      cc
3           ee  ff  ee
4               gg  gg

Я сейчас так использую. но я хотел бы знать, есть ли лучший метод (имя столбца не имеет шаблона, это просто образец)

df["result"] = np.where(df["c1"].notnull(), df["c1"], None)
df["result"] = np.where(df["result"].notnull(), df["result"], df["c2"])
df["result"] = np.where(df["result"].notnull(), df["result"], df["c3"])
df["result"] = np.where(df["result"].notnull(), df["result"], df["c4"])
df["result"] = np.where(df["result"].notnull(), df["result"], "unknown)

Когда столбцов много, этот метод выглядит не очень хорошо.

Ответы [ 4 ]

0 голосов
/ 24 апреля 2018

Я использую lookup и данные из Jpp

df=df.set_index('ID')
s=df.ne('').idxmax(1)
df['Result']=df.lookup(s.index,s)
df
Out[492]: 
   c1  c2  c3  c4 Result
ID                      
1   a   b              a
2      cc  dd         cc
3          ee  ff     ee
4              gg     gg
0 голосов
/ 24 апреля 2018

Настройка

df = df.set_index('ID') # if necessary
df
     c1   c2  c3   c4
ID                   
1     a    b   a  NaN
2   NaN   cc  dd   cc
3   NaN   ee  ff   ee
4   NaN  NaN  gg   gg

Решение
stack + groupby + first
stack неявно отбрасывает NaN, поэтому groupby.first гарантированно даст вам первое ненулевое значение, если оно существует.При возвращении результата все NaN будут выставлены с отсутствующими индексами, которые вы можете fillna с последующим вызовом.

df['result'] = df.stack().groupby(level=0).first()
# df['result'] = df['result'].fillna('unknown') # if necessary 
df
     c1   c2  c3   c4 result
ID                          
1     a    b   a  NaN      a
2   NaN   cc  dd   cc     cc
3   NaN   ee  ff   ee     ee
4   NaN  NaN  gg   gg     gg

(будьте осторожны, для больших фреймов данных это медленно, для производительности вы можете использовать решение @ jezrael)

0 голосов
/ 24 апреля 2018

Один из способов - использовать pd.DataFrame.lookup с pd.Series.first_valid_index, примененным к транспонированному фрейму данных:

df = pd.DataFrame({'ID': [1, 2, 3, 4],
                   'c1': ['a', '', '', ''],
                   'c2': ['b', 'cc', '', ''],
                   'c3': ['' , 'dd', 'ee', ''],
                   'c4': ['', '', 'ff', 'gg']})

df = df.replace('', np.nan)

df['result'] = df.lookup(df.index, df.iloc[:, 1:].T.apply(pd.Series.first_valid_index))

print(df)

   ID   c1   c2   c3   c4 result
0   1    a    b  NaN  NaN      a
1   2  NaN   cc   dd  NaN     cc
2   3  NaN  NaN   ee   ff     ee
3   4  NaN  NaN  NaN   gg     gg
0 голосов
/ 24 апреля 2018

Сначала используйте обратное заполнение NaN с, а затем выберите первый столбец с помощью iloc:

df['result'] = df[['c1','c2','c3','c4']].bfill(axis=1).iloc[:, 0].fillna('unknown')

Или:

df['result'] = df.iloc[:, 1:].bfill(axis=1).iloc[:, 0].fillna('unknown')

print (df)
   ID   c1   c2  c3   c4 result
0   1    a    b   a  NaN      a
1   2  NaN   cc  dd   cc     cc
2   3  NaN   ee  ff   ee     ee
3   4  NaN  NaN  gg   gg     gg

Производительность :

df = pd.concat([df] * 1000, ignore_index=True)


In [220]: %timeit df['result'] = df[['c1','c2','c3','c4']].bfill(axis=1).iloc[:, 0].fillna('unknown')
100 loops, best of 3: 2.78 ms per loop

In [221]: %timeit df['result'] = df.iloc[:, 1:].bfill(axis=1).iloc[:, 0].fillna('unknown')
100 loops, best of 3: 2.7 ms per loop

#jpp solution
In [222]: %%timeit
     ...: cols = df.iloc[:, 1:].T.apply(pd.Series.first_valid_index)
     ...: 
     ...: df['result'] = [df.loc[i, cols[i]] for i in range(len(df.index))]
     ...: 
1 loop, best of 3: 180 ms per loop

#cᴏʟᴅsᴘᴇᴇᴅ'  s solution
In [223]: %timeit df['result'] = df.stack().groupby(level=0).first()
1 loop, best of 3: 606 ms per loop
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...