Pandas DataFrame: копировать содержимое столбца, если он пуст - PullRequest
0 голосов
/ 20 ноября 2018

У меня есть следующий DataFrame с именованными столбцами и индексом:

  'a'     'a*'    'b'    'b*'
1  5      NaN     9      NaN
2  NaN    3       3      NaN
3  4      NaN     1      NaN
4  NaN    9       NaN    7

Из-за источника данных некоторые заголовки столбцов были скопированы немного по-другому.Например, как указано выше, некоторые заголовки столбцов являются строкой, а некоторые - той же строкой с дополнительным символом '*'.

Я хочу скопировать любые значения (которые не являются нулевыми) из a* и *От 1007 * столбцов до a и b соответственно.

Существует ли эффективный способ выполнения такой операции?

Ответы [ 3 ]

0 голосов
/ 20 ноября 2018

Для повышения производительности можно использовать numpy.isnan и преобразовать серии в массивы с числовым значением values:

df['a'] = np.where(np.isnan(df['a'].values), df['a*'].values, df['a'].values)
df['b'] = np.where(np.isnan(df['b'].values), df['b*'].values, df['a'].values)

Другое общее решение, если оно существует толькопары с / без * в столбцах DataFrame и необходимо удалить * столбцы:

Сначала создать MultiIndex с помощью split с добавлением *val:

df.columns = (df.columns + '*val').str.split('*', expand=True, n=1)

И затем выберите DataFrame.xs для фреймов данных, поэтому DataFrame.fillna работает очень хорошо:

df = df.xs('*val', axis=1, level=1).fillna(df.xs('val', axis=1, level=1))
print (df)
     a    b
1  5.0  9.0
2  3.0  3.0
3  4.0  1.0
4  9.0  7.0

Производительность : (зависит от количества пропущенных значений и длины DataFrame)

df = pd.DataFrame({'A': [0, np.nan, 1, 2, 3, np.nan] * 10000, 
                   'A*': [4, 4, 5, 6, 7, 8] * 10000})

def using_fillna(df):
    df['A'] = df['A'].fillna(df['A*'])
    return df

def using_np_where(df):
    df['B'] = np.where(df['A'].isnull(), df['A*'], df['A'])
    return df

def using_np_where_numpy(df):
    df['C'] = np.where(np.isnan(df['A'].values), df['A*'].values, df['A'].values)
    return df

def using_combine_first(df):
    df['D'] = df['A'].combine_first(df['A*'])
    return df

%timeit -n 100 using_fillna(df)
%timeit -n 100 using_np_where(df)
%timeit -n 100 using_combine_first(df)
%timeit -n 100 using_np_where_numpy(df)

1.15 ms ± 89.6 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
533 µs ± 13.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
591 µs ± 38.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
423 µs ± 21.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
0 голосов
/ 20 ноября 2018

Использование fillna() намного медленнее, чем np.where, но имеет преимущество только в pandas.Если вы хотите более быстрый метод и сохраняете его pandas в чистом виде, вы можете использовать combine_first(), который в соответствии с документацией используется для:

Объединения значений серии, выбираясначала вызываем значения СерииИндекс результата будет объединением двух индексов

Перевод: это метод, предназначенный для точного выполнения заданного в вопросе вопроса.

Как его использовать?

df['a'].combine_first(df['a*'])

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

df = pd.DataFrame({'A': [0, None, 1, 2, 3, None] * 10000, 'A*': [4, 4, 5, 6, 7, 8] * 10000})

def using_fillna(df):
    return df['A'].fillna(df['A*'])

def using_combine_first(df):
    return df['A'].combine_first(df['A*'])

def using_np_where(df):
    return np.where(df['A'].isnull(), df['A*'], df['A'])

def using_np_where_numpy(df):
    return np.where(np.isnan(df['A'].values), df['A*'].values, df['A'].values)

%timeit -n 100 using_fillna(df)
%timeit -n 100 using_combine_first(df)
%timeit -n 100 using_np_where(df)
%timeit -n 100 using_np_where_numpy(df)

1.34 ms ± 71.5 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
281 µs ± 15.7 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
257 µs ± 16.4 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
166 µs ± 10.8 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
0 голосов
/ 20 ноября 2018

Использование np.where

df['a']= np.where(df['a'].isnull(), df['a*'], df['a'])
df['b']= np.where(df['b'].isnull(), df['b*'], df['b'])

Выход:

     a  a*  b   b*
0   5.0 NaN 9.0 NaN
1   3.0 3.0 3.0 NaN
2   4.0 NaN 1.0 NaN
3   9.0 9.0 7.0 7.0
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...