Как объединить столбцы после группировки и выбрать первое допустимое значение других столбцов в кадре данных Pandas? - PullRequest
0 голосов
/ 07 декабря 2018

У меня есть файл данных pandas в форме:

df

    ID    col_1    col_2    col_3    Date
     1              20       40      1/1/2018
     1     10                        1/2/2018
     1     50                60      1/3/2018
     3     40       10       90      1/1/2018
     4              80       80      1/1/2018

Проблема в том, что мне нужно создать новый кадр данных с первыми действительными значениямидля каждого столбца, НО также дополнительные столбцы, полученные из «Дата», которые соответствуют времени, когда эти значения были сопоставлены в исходном кадре данных.

Другими словами:

new_df

    ID    first_col_1    Date_col_1    first_col_2    Date_col_2    first_col_3    Date_col_3
    1         10          1/2/2018          20         1/1/2018         40         1/1/2018 
    3         40          1/1/2018          10         1/1/2018         90         1/1/2018 
    4                     1/1/2018          80         1/1/2018         80         1/1/2018

Я понимаю, что получение первого действительного значения для каждого столбца для каждого идентификатора так же просто, как

df.groupby('ID').first()

Но как извлечь соответствующую информацию «Дата» для каждого столбца?

Ответы [ 3 ]

0 голосов
/ 07 декабря 2018

IIUC с использованием melt до groupby

newdf=df.melt(['ID','Date']).loc[lambda x : x.value!='']

newdf=  newdf.groupby(['ID','variable']).first().unstack().sort_index(level=1,axis=1)

newdf.columns=newdf.columns.map('_'.join)
newdf
   Date_col_1  value_col_1 Date_col_2  value_col_2 Date_col_3  value_col_3
ID                                                                        
1    1/2/2018         10.0   1/1/2018         20.0   1/1/2018         40.0
3    1/1/2018         40.0   1/1/2018         10.0   1/1/2018         90.0
4        None          NaN   1/1/2018         80.0   1/1/2018         80.0
0 голосов
/ 07 декабря 2018

Вам не нужно зацикливаться, но вам нужно «растопить» ваш фрейм данных перед операцией группировки.

Итак, начиная с:

from io import StringIO
import pandas
f = StringIO("""\
ID,col_1,col_2,col_3,Date
1,,20,40,1/1/2018
1,10,,,1/2/2018
1,50,,60,1/3/2018
3,40,10,90,1/1/2018
4,,80,80,1/1/2018
""")

df = pandas.read_csv(f)

Вы можете затем:

print(
    df.melt(id_vars=['ID', 'Date'], value_vars=['col_1', 'col_2', 'col_3'], value_name='first')
      .groupby(by=['ID', 'variable'])
      .first()
      .unstack(level='variable')
)

Что дает вам:

              Date                     first            
variable     col_1     col_2     col_3 col_1 col_2 col_3
ID                                                      
1         1/1/2018  1/1/2018  1/1/2018  10.0  20.0  40.0
3         1/1/2018  1/1/2018  1/1/2018  40.0  10.0  90.0
4         1/1/2018  1/1/2018  1/1/2018   NaN  80.0  80.0

Столбцы многоуровневые, так что вы можете их немного полировать, если хотите:

def flatten_columns(df, sep='_'):
    newcols = [sep.join(_) for _ in df.columns]
    return df.set_axis(newcols, axis='columns', inplace=False)

print(
    df.melt(id_vars=['ID', 'Date'], value_vars=['col_1', 'col_2', 'col_3'], value_name='first')
      .groupby(by=['ID', 'variable'])
      .first()
      .unstack(level='variable')
      .sort_index(level='variable', axis='columns')
      .pipe(flatten_columns)
)

Что дает вам что-то с не совсем тем же порядком столбцов, что и в вашем примере, но это настолько близко, насколько мне кажется, сделать это.

   Date_col_1  first_col_1 Date_col_2  first_col_2 Date_col_3  first_col_3
ID                                                                        
1    1/1/2018         10.0   1/1/2018         20.0   1/1/2018         40.0
3    1/1/2018         40.0   1/1/2018         10.0   1/1/2018         90.0
4    1/1/2018          NaN   1/1/2018         80.0   1/1/2018         80.0
0 голосов
/ 07 декабря 2018

Я думаю, вам нужно перебрать столбцы и извлечь первые значения для каждого из них перед объединением.Я не вижу более простого способа сделать это.

# Create a list to store the dataframes you want for each column
sub_df = [pd.DataFrame(df['ID'].unique(), columns=['ID'])]  # Init this list with IDs

for col in df.columns[1:-1]:  # loop over the columns (except ID and Date)

    # Determine the first valid rows indexes for this column (group by ID)
    valid_rows = df.groupby('ID')[col].apply(lambda sub_df: sub_df.first_valid_index())

    # Extracting the values and dates corresponding to these rows
    new_sub_df = df[[col, 'Date']].ix[valid_rows].reset_index(drop=True)

    # Append to the list of sub DataFrames
    sub_df.append(new_sub_df)

# Concatenate all these DataFrames.
new_df = pd.concat(sub_df, axis=1)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...