Объедините столбцы Pandas, содержащие объекты списка - PullRequest
0 голосов
/ 16 сентября 2018

Мой вопрос похож на ' Объединить столбцы строк панд с пропущенными значениями ' и ' Как объединить / объединить столбцы в пандах? ', но поскольку ячейки, которые я хочу объединить, содержатсписки, все приведенные ответы не работают.

Упрощенно, мой df выглядит так:

        players    players1    players2    players3
1       ['1','2']  
2       ['2','4']
3                  ['1','4']
4                              ['1','5']
5                                          ['3','5']
6
7                  ['3','4']

(так что я знаю, что в двух столбцах никогда не будет значений).

Теперь я хочу добавитьновый столбец, объединяющий списки:

        players    players1    players2    players3     players_combine
1       ['1','2']                                       ['1','2']
2       ['2','4']                                       ['2','4']
3                  ['1','4']                            ['1','4']
4                              ['1','5']                ['1','5']
5                                          ['3','5']    ['3','5']
6
7                  ['3','4']                            ['3','4']

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

df['players_combine'] = np.where(df.players.notnull(),df.players.values,np.where(df.players1.notnull(),df.players1.values,np.where(df.players2.notnull(),df.players2.values,np.where(df.players3.notnull(),df.players3.values,np.nan))))

РЕДАКТИРОВАТЬ: Как и просили в комментариях: df.head (5) .to_dict ()

{'players': {'5b41800eaffb061b88c4beac': ['57005', '124021', '132037', '78523', '111742', '133892', '76431', '78066', '138749', '132358', '77857', '69756', '133745', '278877', '247798', '108106', '127464', '296770'], '5b41800eaffb061b88c4bead': ['18929', '110183', '28401', '302853', '296768', '94912', '93671', '52060', '43282', '132364', '140646', '77861', '19787', '133790', '312666', '76336', '317219', '137849'], '5b41800daffb061b88c4bc7f': 'nan', '5b41800eaffb061b88c4bd62': 'nan', '5b41800eaffb061b88c4bd65': 'nan'}, 'players1': {'5b41800eaffb061b88c4beac': nan, '5b41800eaffb061b88c4bead': nan, '5b41800daffb061b88c4bc7f': ['57005', '124021', '132037', '78523', '111742', '133892', '296770', '78066', '138749', '132358', '77857', '69756', '133745', '278877', '247798', '108106', '127464', '76431'], '5b41800eaffb061b88c4bd62': '', '5b41800eaffb061b88c4bd65': ''}, 'players2': {'5b41800eaffb061b88c4beac': nan, '5b41800eaffb061b88c4bead': nan, '5b41800daffb061b88c4bc7f': nan, '5b41800eaffb061b88c4bd62': ['57005', '124021', '132037', '78523', '111742', '133892', '296770', '108106', '138749', '132358', '77857', '69756', '133745', '278877', '247798', '78066', '127464', '76431'], '5b41800eaffb061b88c4bd65': ''}, 'players3': {'5b41800eaffb061b88c4beac': nan, '5b41800eaffb061b88c4bead': nan, '5b41800daffb061b88c4bc7f': nan, '5b41800eaffb061b88c4bd62': nan, '5b41800eaffb061b88c4bd65': ['57005', '124021', '132037', '78523', '111742', '133892', '296770', '108106', '138749', '132358', '247798', '69756', '133745', '278877', '77857', '78066', '127464', '76431']}}

Ответы [ 4 ]

0 голосов
/ 19 сентября 2018

Поскольку в моем коде была проблема с неверно отформатированными данными, а не с заданным вопросом, я хотел добавить некоторую информацию о производительности всех различных опций.Я использовал np.where, потому что он использует векторизацию, тогда как np.apply выполняет итерацию по строкам, и поэтому существует огромная разница в производительности.


Настройка test-df с 4 * 2000 = 8000 строк:

import pandas as pd
import numpy as np

l = [[['1','2'],np.NaN,np.NaN,np.NaN],
     [np.NaN,['2','3'],np.NaN,np.NaN],
    [np.NaN,np.NaN,['3','4'],np.NaN],
    [np.NaN,np.NaN,np.NaN,['4','5']]]

l=l*2000

df = pd.DataFrame(l)

df.columns = ['players','players1','players2','players3']

Лучший вариант:

%timeit df['players_combine'] = np.where(df.players.notnull(),df.players.values,np.where(df.players1.notnull(),df.players1.values,np.where(df.players2.notnull(),df.players2.values,np.where(df.players3.notnull(),df.players3.values,np.nan))))

100 loops, best of 3: 2.18 ms per loop

Очень хороший вариант:

%timeit df.loc[df.notnull().any(axis=1)]\
  .apply(lambda x: x[x.first_valid_index()], axis=1)

100 loops, best of 3: 413 ms per loop

Другой вариант 1:

%timeit df['players_combine'] = df.agg(lambda s: s[~s.isnull()][0], axis=1)

1 loop, best of 3: 4.71 s per loop

И 2:

%timeit df['players_combine'] = df.apply(lambda x: x[x.notnull()].max(), axis=1)

1 loop, best of 3: 4.86 s per loop
0 голосов
/ 16 сентября 2018

Поскольку вы знаете, что для каждой строки вы будете иметь значение не более одного столбца, вы можете заменить значения, которые вам не нужны, на NaN, а затем использовать .stack.

В этом случае похоже, что у вас есть строки 'nan' и '', которые должны быть заменены сначала np.NaN.

import numpy as np

df['players_combine'] = df.replace({'': np.NaN, 'nan': np.NaN}, regex=True).stack().reset_index(level=1, drop=True)

Пример данных

import pandas as pd
df = pd.DataFrame({'players': [['1','2'], '', '', np.NaN, ''],
                   'players1': ['', ['2','4'], '', np.NaN, ''],
                   'players2': ['', '', ['1','5'], np.NaN, ''],
                   'players3': ['', '', np.NaN, ['3', '5'], '']})

Выход:

  players players1 players2 players3 players_combine
0  [1, 2]                                     [1, 2]
1           [2, 4]                            [2, 4]
2                    [1, 5]      NaN          [1, 5]
3     NaN      NaN      NaN   [3, 5]          [3, 5]
4                                                NaN
0 голосов
/ 16 сентября 2018

Анализируя ваш df.to_dict(), кажется, что для некоторых ячеек у вас есть строка nan, для других у вас есть действительный np.nan, а для некоторых других у вас даже есть пустые строки ''.

Итак, сначала очистите ваш набор данных, сделав единообразные нулевые значения:

df = df.replace({'nan':np.nan, '':np.nan})

Тогда вы можете aggregate через axis=1

df['players_combine'] = df.agg(lambda s: s[~s.isnull()][0], axis=1)
0 голосов
/ 16 сентября 2018

Если какая-либо из пустых ячеек является пустой строкой (''), сначала задайте для нее значение NaN:

df[df==''] = np.nan

Затем выберите максимум всех не-NaN в каждой строке:

df.apply(lambda x: x[x.notnull()].max(), axis=1)
#1    [1, 2]
#2    [2, 4]
#3    [1, 4]
#4    [1, 5]
#5    [3, 5]
#6       NaN
#7    [3, 4]

Другое интересное (и более быстрое ) решение состоит в том, чтобы исключить все-NaN строки и затем найти первое допустимое значение в каждой строке:

df.loc[df.notnull().any(axis=1)]\
  .apply(lambda x: x[x.first_valid_index()], axis=1)
#1    [1, 2]
#2    [2, 4]
#3    [1, 4]
#4    [1, 5]
#5    [3, 5]
#7    [3, 4]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...