2016-09-07 7 views
3

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

Address1  Address2  Address3  Address4  Phone1  Phone2  Phone3  Phone4 
ABC   nan   def   nan   9091-XYz nan  nan  XYZ-ABZ 

Должно быть столбец сдвинуты на что-то вроде

Address1  Address2  Address3  Address4  Phone1  Phone2  Phone3  Phone4 
ABC   def   nan   nan   9091-XYz XYZ-ABZ nan  nan 

Там другая question который решает подобную проблему.

pdf = pd.read_csv('Data.txt',sep='\t') 

# gets a set of columns removing the numerical part 
columns = set(map(lambda x : x.rstrip(''),pdf.columns)) 

for col_pattern in columns: 
    # get columns with similar names 
    current = [col for col in pdf.columns if col_pattern in col] 
    coldf= pdf[current] 
    # shift columns to the left 

Файл Data.txt имеет столбцы, упорядоченные по именам столбцов, так что все столбцы с схожими названиями.

Любая помощь с этим ценится

я попытался добавить это в коде выше от линии, которая выбежала из памяти:

newdf=pd.read_csv(StringIO(u''+re.sub(',+',',',df.to_csv()).decode('utf-8'))) 
    list_.append(newdf) 
pd.concat(list_,axis=0).to_csv('test.txt') 

ответ

3

Решения с MultiIndex и dropna:

import pandas as pd 
import numpy as np 

df = pd.DataFrame({'Address1': {0: 'ABC', 1: 'ABC'}, 
        'Address2': {0: np.nan, 1: np.nan}, 
        'Address3': {0: 'def', 1: 'def'}, 
        'Phone4': {0: 'XYZ-ABZ', 1: 'XYZ-ABZ'}, 
        'Address4': {0: np.nan, 1: np.nan}, 
        'Phone1': {0: '9091-XYz', 1: 'Z9091-XYz'}, 
        'Phone3': {0: np.nan, 1: 'aaa'}, 
        'Phone2': {0: np.nan, 1: np.nan}}) 

print (df) 
    Address1 Address2 Address3 Address4  Phone1 Phone2 Phone3 Phone4 
0  ABC  NaN  def  NaN 9091-XYz  NaN NaN XYZ-ABZ 
1  ABC  NaN  def  NaN Z9091-XYz  NaN aaa XYZ-ABZ 
#multiindex from columns of df 
cols = df.columns.str.extract('([[A-Za-z]+)(\d+)', expand=True).values.tolist() 

mux = pd.MultiIndex.from_tuples(cols) 
df.columns = mux 
print (df) 
    Address     Phone     
     1 2 3 4   1 2 3  4 
0  ABC NaN def NaN 9091-XYz NaN NaN XYZ-ABZ 
1  ABC NaN def NaN Z9091-XYz NaN aaa XYZ-ABZ 

#unstack, remove NaN rows, convert to df (because cumcount) 
df1 = df.unstack().dropna().reset_index(level=1, drop=True).to_frame() 
#create new level of index 
df1['g'] = (df1.groupby(level=[0,1]).cumcount() + 1).astype(str) 
#add column g to multiindex 
df1.set_index('g', append=True, inplace=True) 
#reshape to original 
df1 = df1.unstack(level=[0,2]) 
#remove first level of multiindex of column (0 from to_frame) 
df1.columns = df1.columns.droplevel(0) 
#reindex and replace None to NaN 
df1 = df1.reindex(columns=mux).replace({None: np.nan}) 
#'reset' multiindex in columns 
df1.columns = [''.join(col) for col in df1.columns] 
print (df1) 
    Address1 Address2 Address3 Address4  Phone1 Phone2 Phone3 Phone4 
0  ABC  def  NaN  NaN 9091-XYz XYZ-ABZ  NaN  NaN 
1  ABC  def  NaN  NaN Z9091-XYz  aaa XYZ-ABZ  NaN 

Старым решение:

Я нахожу еще одну проблему - решение выше doest работает правильно, если больше строк в DataFrame. Таким образом, вы можете использовать double apply. Но проблема этого решения является uncorrect порядок значений в строках:

df = pd.DataFrame({'Address1': {0: 'ABC', 1: 'ABC'}, 'Address2': {0: np.nan, 1: np.nan}, 'Address3': {0: 'def', 1: 'def'}, 'Phone4': {0: 'XYZ-ABZ', 1: 'XYZ-ABZ'}, 'Address4': {0: np.nan, 1: np.nan}, 'Phone1': {0: '9091-XYz', 1: '9091-XYz'}, 'Phone3': {0: np.nan, 1: 'aaa'}, 'Phone2': {0: np.nan, 1: np.nan}}) 

print (df) 
    Address1 Address2 Address3 Address4 Phone1 Phone2 Phone3 Phone4 
0  ABC  NaN  def  NaN 9091-XYz  NaN NaN XYZ-ABZ 
1  ABC  NaN  def  NaN 9091-XYz  NaN aaa XYZ-ABZ 

cols = df.columns.str.extract('([[A-Za-z]+)(\d+)', expand=True).values.tolist() 
mux = pd.MultiIndex.from_tuples(cols) 
df.columns = mux 

df = df.groupby(axis=1, level=0) 
     .apply(lambda x: x.apply(lambda y: y.sort_values().values, axis=1)) 

df.columns = [''.join(col) for col in df.columns] 
print (df) 
    Address1 Address2 Address3 Address4 Phone1 Phone2 Phone3 Phone4 
0  ABC  def  NaN  NaN 9091-XYz XYZ-ABZ NaN  NaN 
1  ABC  def  NaN  NaN 9091-XYz XYZ-ABZ aaa  NaN 

Также я пытаюсь изменить piRSquared решение - то вам не нужно MultiIndex:

coltype = df.columns.str.extract(r'([[A-Za-z]+)', expand=False) 
print (coltype) 
Index(['Address', 'Address', 'Address', 'Address', 'Phone', 'Phone', 'Phone', 
     'Phone'], 
     dtype='object') 

df = df.groupby(coltype, axis=1) 
     .apply(lambda x: x.apply(lambda y: y.sort_values().values, axis=1)) 
print (df) 
    Address1 Address2 Address3 Address4 Phone1 Phone2 Phone3 Phone4 
0  ABC  def  NaN  NaN 9091-XYz XYZ-ABZ NaN  NaN 
1  ABC  def  NaN  NaN 9091-XYz XYZ-ABZ aaa  NaN 
+0

Использование мультииндексации на выборке дает выход примерно в 3 раза, меньше времени. –

+0

Да, но, возможно, есть еще одна проблема - все NaN в одном столбце? Или иногда некоторые значения в некотором столбце являются NaN и другими значениями? – jezrael

+0

Я думаю 'df = pd.DataFrame ({'Address1': {0: 'ABC', 1: 'ABC'}, 'Address2': {0: np.nan, 1: np.nan}, 'Address3' : {0: 'def', 1: 'def'}, 'Phone4': {0: 'XYZ-ABZ', 1: 'XYZ-ABZ'}, 'Address4': {0: np.nan, 1: np.nan}, 'Phone1': {0: '9091-XYz', 1: '9091-XYz'}, 'Phone3': {0: np.nan, 1: 'aaa'}, 'Phone2': { 0: np.nan, 1: np.nan}}) ', см. Вторую строку с' Phone3' – jezrael

2

pushna
выталкивает все нулевые значения конец серии

coltype
Использует regex для извлечения нечислового префикс из всех имен столбцов

def pushna(s): 
    notnull = s[s.notnull()] 
    isnull = s[s.isnull()] 
    values = notnull.append(isnull).values 
    return pd.Series(values, s.index) 

coltype = df.columns.to_series().str.extract(r'(\D*)', expand=False) 

df.groupby(coltype, axis=1).apply(lambda df: df.apply(pushna, axis=1)) 

enter image description here

+0

У меня есть CSV-файл с 2,5 лакх строк. Запустили его. Надеюсь, это скоро будет сделано. –