Как быстро заполнить значения NaN в строке значениями в списке похожих строк - PullRequest
0 голосов
/ 25 декабря 2018

У меня большой Dataframe (около 800 000 строк).Почти 30% строк имеют значения NaN, например,

test = pd.DataFrame({"name": [1,2,3,4,5,6,7], 
                     "col1": ['c1', 'c2', 'c3', 'c4', 'c5', 'c6', 'c7'], 
                     "col2": [4, 5, 6, np.nan, np.nan, 8, 5], 
                     "col3": [7, 8, 9, np.nan, np.nan, 3, 7], 
                     "col4": [7, 8, 9, np.nan, np.nan, 2, 6]})

    name  col1  col2   col3  col4    
0    1     c1    4.0    7.0   7.0
1    2     c2    5.0    8.0   8.0    
2    3     c3    6.0    9.0   9.0    
3    4     c4    NaN    NaN   NaN    
4    5     c5    NaN    NaN   NaN    
5    6     c6    8.0    3.0   2.0    
6    7     c7    5.0    7.0   6.0

Теперь у меня есть NaN в row3 и row4.

И, основываясь на некоторых правилах, я получаю наиболее похожие строки для строки 3:

similar_for_row3 = ['name' = 10, 'name' = 3, 'name' = 1]

и для строки 4

similar_for_row4 = ['name' = 2, 'name' = 6, 'name' = 20].

Тогда мои вопросы:

  1. как я могу быстро проверить, находятся ли эти строки в similar_for_row3 и similar_for_row4 в кадре данных, например, 'name' = 10 и 'name' = 20 не в нем.

  2. быстро заменяет значения NaN в строке на значения в аналогичных строках.Например, для row3 мы сначала проверяем все строки в similar_for_row3, а затем используем первую строку, существовавшую в кадре данных (то есть test.loc[test['name' == 3]]), чтобы заменить NaN в row3.

Вывод:

    name  col1  col2   col3  col4    
0    1     c1    4.0    7.0   7.0    
1    2     c2    5.0    8.0   8.0    
2    3     c3    6.0    9.0   9.0    
3    4     c4    6.0    9.0   9.0  -> replace NaN with 'name' = 3    
4    5     c5    NaN    NaN   NaN    
5    6     c6    8.0    3.0   2.0    
6    7     c7    5.0    7.0   6.0

Я попытался перебрать весь Dataframe с помощью цикла for, чтобы заменить значения NaN, но это очень медленно.Это займет у меня около 3 секунд, чтобы заменить один ряд.И мой набор данных имеет 800 000 строк.Это будет стоить мне месяц, чтобы сделать это.Пожалуйста, помогите!

1 Ответ

0 голосов
/ 25 декабря 2018
  1. Как я могу быстро проверить, находятся ли эти строки в Similar_for_row3 и Similar_for_row4 в кадре данных, например, «name» = 10 и «name» = 20 в нем.

Вы можете найти пересечение двух sets, используя &, и использовать sorted настройку key= similar_for_row3.index, чтобы использовалось первое пересечение, которое появляется в similar_for_row3:

similar_for_row4 = [2, 6, 20]
fill_with  = sorted(list(set(similar_for_row4) & set(test.name.values)), 
       key= similar_for_row4.index)[0]
#2

Таким образом, здесь строка 2 будет использоваться для замены строки 4, как вы упомянули «первую строку, существовавшую в кадре данных».

Быстро заменить значения NaN в строке значениями в аналогичных строках.Например, для row3 мы сначала проверяем все строки в Similar_for_row3, а затем используем первую строку, существовавшую в Dataframe (которая является test.loc [test ['name' == 3]]), чтобы заменить NaN в row3.

Сначала вы можете создать маску, используя .isnull(), на кадре данных, нарезанном на определенной строке, и выполнить логическую индексацию на кадре данных, чтобы отфильтровать соответствующие столбцы с теми, в которыхcase, строка 2:

row = 4
mask = test.loc[row, :].isnull().squeeze()
test.loc[row, mask] = test.loc[fill_with, mask].values

Таким образом, для этого примера у вас будет:

    name col1 col2  col3  col4
0     1   c1   4.0   7.0   7.0
1     2   c2   5.0   8.0   8.0
2     3   c3   6.0   9.0   9.0
3     4   c4   NaN   NaN   NaN
4     5   c5   6.0   9.0   9.0
5     6   c6   8.0   3.0   2.0
6     7   c7   5.0   7.0   6.0

Обновление

Для того, чтобы легко обнаружитьстроки, в которых присутствуют какие-либо NaN, вы можете сделать:

has_nans = test[test.isnull().any(axis=1)].index.values

И просто зацикливаться на has_nans, находя наиболее похожую строку для замены в каждой итерации.

...