Удлинение DataFrame на основе размещения столбцов внутри него в Pandas - PullRequest
0 голосов
/ 23 мая 2018

Я ищу функцию, которая достигает следующего.Это лучше всего показано на примере.Рассмотрим:

pd.DataFrame([ [1, 2, 3 ], [4, 5, np.nan ]], columns=['x', 'y1', 'y2'])

, который выглядит следующим образом:

   x  y1   y2
0  1   2  3
1  4   5  NaN

Я хотел бы свернуть столбцы y1 и y2, удлиняя DataFame, где это необходимо, чтобы вывод:

   x  y
0  1   2  
1  1   3  
2  4   5  

То есть по одной строке для каждой комбинации между x и y1 или x и y2.Я ищу функцию, которая делает это относительно эффективно, так как у меня есть несколько y s и много строк.

Ответы [ 3 ]

0 голосов
/ 23 мая 2018

Повторите все элементы в первом столбце, основываясь на количестве ненулевых значений в каждой строке.Затем просто создайте свой окончательный фрейм данных, используя оставшиеся ненулевые значения в других столбцах.Вы можете использовать метод DataFrame.count() для подсчета ненулевых значений и numpy.repeat() для повторения массива на основе соответствующего массива подсчета.

>>> rest = df.loc[:,'y1':]
>>> pd.DataFrame({'x': np.repeat(df['x'], rest.count(1)).values,
                  'y': rest.values[rest.notna()]})

Демо:

>>> df
    x   y1   y2   y3   y4
0   1  2.0  3.0  NaN  6.0
1   4  5.0  NaN  9.0  3.0
2  10  NaN  NaN  NaN  NaN
3   9  NaN  NaN  6.0  NaN
4   7  6.0  NaN  NaN  NaN

>>> rest = df.loc[:,'y1':]
>>> pd.DataFrame({'x': np.repeat(df['x'], rest.count(1)).values,
                  'y': rest.values[rest.notna()]})
   x    y
0  1  2.0
1  1  3.0
2  1  6.0
3  4  5.0
4  4  9.0
5  4  3.0
6  9  6.0
7  7  6.0
0 голосов
/ 23 мая 2018

Вы можете использовать stack, чтобы добиться цели, т.е.

pd.DataFrame(df.set_index('x').stack().reset_index(level=0).values,columns=['x','y'])

     x    y
0  1.0  2.0
1  1.0  3.0
2  4.0  5.0
0 голосов
/ 23 мая 2018

Вот один из них, основанный на NumPy, поскольку вы искали производительность -

def gather_columns(df):
    col_mask = [i.startswith('y') for i in df.columns]
    ally_vals = df.iloc[:,col_mask].values
    y_valid_mask = ~np.isnan(ally_vals)

    reps = np.count_nonzero(y_valid_mask, axis=1)
    x_vals = np.repeat(df.x.values, reps)
    y_vals = ally_vals[y_valid_mask]
    return pd.DataFrame({'x':x_vals, 'y':y_vals})

Пример выполнения -

In [78]: df #(added more cols for variety)
Out[78]: 
   x  y1   y2   y5   y7
0  1   2  3.0  NaN  NaN
1  4   5  NaN  6.0  7.0

In [79]: gather_columns(df)
Out[79]: 
   x    y
0  1  2.0
1  1  3.0
2  4  5.0
3  4  6.0
4  4  7.0

Если столбцы y всегда начинаются со второго столбцавплоть до конца, мы можем просто нарезать фрейм данных и, следовательно, получить дальнейшее повышение производительности, например, -

def gather_columns_v2(df):
    ally_vals = df.iloc[:,1:].values
    y_valid_mask = ~np.isnan(ally_vals)

    reps = np.count_nonzero(y_valid_mask, axis=1)
    x_vals = np.repeat(df.x.values, reps)
    y_vals = ally_vals[y_valid_mask]
    return pd.DataFrame({'x':x_vals, 'y':y_vals})
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...