Я хочу изменить порядок значений имен столбцов, содержащих Nan.

Условие, которое я хочу, заключается в том, что если строка в списке соответствует столбцу [1], он будет повторно сдвигать только значения столбцов, которые содержат строку под совпадающей строкой, поэтому это мой фрейм данных перед смещением.

[in] : df
[Out]:

   column1     column2    column3 
0  aba abab    800.0      900.0
1  aaa acc     900.0      60.0 
2  bba jka     809.0      400.0
3  fff yy      521.0      490.0  
4  hkm asa j   290.0      321.0    
5  daa rr oo   88.0       Nan
6  jtuy ww ddw Nan        600.0
8  bkam ftf    Nan        Nan   
9  fgqefc      Nan        Nan
10 daas we fg  Nan        Nan   
11 judv mm mk  Nan        Nan   
12 hus gg hhh  Nan        Nan 

И вот мой список

my_list= ['bba jka', 'hkm asa j']

Так что это мой фрейм данных, который я хотел, имя которого df1

column1     column2    column3 
0  aba abab    800.0      900.0
1  aaa acc     900.0      60.0 
2  bba jka     Nan        Nan
3  fff yy      809.0      400.0  
4  hkm asa j   Nan        Nan    
5  daa rr oo   521.0      490.0
6  jtuy ww ddw 290.0      321.0
8  bkam ftf    88.0       Nan   
9  fgqefc      Nan        600.0
10 daas we fg  Nan        Nan   
11 judv mm mk  Nan        Nan   
12 hus gg hhh  Nan        Nan 

Я не понимаю, как добиться df1 с помощью shift и match, кто-нибудь может это решить?

0
M Rifky Ferdiand 10 Ноя 2020 в 06:30

1 ответ

Лучший ответ

Вот предложение, которое может быть неоптимальным:

Шаг 1 : Подготовка к apply:

match = df['column1'].str.fullmatch('|'.join(entry for entry in my_list))
df['shift'] = match.cumsum()
df['index'] = df.index
df.set_index('column1', drop=True, inplace=True)

Результат (df) выглядит так:

            column2 column3  shift  index
column1                                  
aba abab      800.0   900.0      0      0
aaa acc       900.0    60.0      0      1
bba jka       809.0   400.0      1      2
fff yy        521.0   490.0      1      3
hkm asa j     290.0   321.0      2      4
daa rr oo      88.0     NaN      2      5
...

Шаг 2 : "Сдвиг" через apply и NaN назначение через маску match:

df = df.apply(lambda row: df.shift(int(row.at['shift'])).iloc[int(row.at['index'])],
              axis='columns')
df[list(match)] = np.nan

Шаг 3 . Очистите:

df.drop(['shift', 'index'], axis='columns', inplace=True)
df.reset_index(inplace=True)

Надеемся, результат такой, как ожидалось:

        column1 column2 column3
0      aba abab   800.0   900.0
1       aaa acc   900.0    60.0
2       bba jka     NaN     NaN
3        fff yy   809.0   400.0
4     hkm asa j     NaN     NaN
5     daa rr oo   521.0   490.0
6   jtuy ww ddw   290.0   321.0
7      bkam ftf    88.0     NaN
8        fgqefc     NaN   600.0
9    daas we fg     NaN     NaN
10   judv mm mk     NaN     NaN
11   hus gg hhh     NaN     NaN

Но мне не нравится использование df.shift в apply. Проблема в том, что возможное совпадение в первой строке приведет к ложному результату без shift. Вот версия, которая позволяет избежать этой проблемы и более прямолинейна в apply:

# Preparation
df = pd.concat(
        [pd.DataFrame({col: ['NOT IN LIST' if i == 0 else np.nan]
                       for i, col in enumerate(df.columns)}), df],
        axis='index', 
        ignore_index=True
    )
match = df['column1'].str.fullmatch('|'.join(entry for entry in my_list))
df['shift'] = df.index - match.cumsum()
df.set_index('column1', drop=True, inplace=True)

# Shifting etc.
df = df.apply(lambda row: df.iloc[int(row.at['shift'])], axis='columns')
df[list(match)] = np.nan

# Clean up
df.drop('NOT IN LIST', axis='index', inplace=True)
df.drop('shift', axis='columns', inplace=True)
df.reset_index(inplace=True)

(Здесь предполагается, что строка 'NOT IN LIST' не входит в my_list. Скорее всего, пустая строка '' тоже будет хорошим выбором.)

1
Timus 11 Ноя 2020 в 12:02