Сделать pandas DataFrame в dict и dropna

У меня есть несколько панд DataFrame с NaN. Как 9X_pandas это:

import pandas as pd import numpy as np raw_data={'A':{1:2,2:3,3:4},'B':{1:np.nan,2:44,3:np.nan}} data=pd.DataFrame(raw_data) >>> data A B 1 2 NaN 2 3 44 3 4 NaN 

Теперь я хочу сделать из этого диктат 9X_python-interpreter и одновременно удалить NaN. Результат должен 9X_py выглядеть так:

{'A': {1: 2, 2: 3, 3: 4}, 'B': {2: 44.0}} 

Но использование функции pandas 9X_pd to_dict дает мне такой результат:

>>> data.to_dict() {'A': {1: 2, 2: 3, 3: 4}, 'B': {1: nan, 2: 44.0, 3: nan}} 

Итак, как 9X_python-shell сделать диктант из DataFrame и избавиться 9X_py от NaN?

37
0
9
Общее количество ответов: 9

Ответ #1

Ответ на вопрос: Сделать pandas DataFrame в dict и dropna

Есть много способов добиться этого. Я потратил 9X_pandas некоторое время на оценку производительности 9X_python-interpreter на не очень большом (70 КБ) фреймворке данных. Хотя 9X_python ответ @ der_die_das_jojo работает, он также 9X_py довольно медленный.

Ответ, предложенный this question, на 9X_py самом деле оказывается примерно в 5 раз 9X_pandas быстрее на большом фрейме данных.

В моем 9X_python-shell тестовом фрейме данных (df):

Метод выше:

%time [ v.dropna().to_dict() for k,v in df.iterrows() ] CPU times: user 51.2 s, sys: 0 ns, total: 51.2 s Wall time: 50.9 s 

Еще 9X_python один медленный метод:

%time df.apply(lambda x: [x.dropna()], axis=1).to_dict(orient='rows') CPU times: user 1min 8s, sys: 880 ms, total: 1min 8s Wall time: 1min 8s 

Самый быстрый способ, который 9X_py я смог найти:

%time [ {k:v for k,v in m.items() if pd.notnull(v)} for m in df.to_dict(orient='rows')] CPU times: user 14.5 s, sys: 176 ms, total: 14.7 s Wall time: 14.7 s 

Формат этого вывода представляет 9X_py собой словарь, ориентированный на строки, вам 9X_py может потребоваться внести изменения, если 9X_pandas вы хотите использовать в вопросе форму, ориентированную 9X_pandas на столбцы.

Очень интересно, найдет ли кто 9X_pythonista еще более быстрый ответ на этот вопрос.

30
0

Ответ #2

Ответ на вопрос: Сделать pandas DataFrame в dict и dropna

Первый график генерирует словари по столбцам, поэтому 9X_python-interpreter на выходе получается несколько очень длинных 9X_python-shell словарей, количество слов зависит от количества 9X_pythonista столбцов.

Я тестирую несколько методов с 9X_python-shell помощью perfplot, и самый быстрый метод - это цикл 9X_pythonic по каждому столбцу и удаление отсутствующих 9X_pythonic значений или None с помощью Series.dropna или с помощью Series.notna в 9X_python-shell boolean indexing в более крупных DataFrames.

Меньше DataFrames 9X_pythonic - это самый быстрый способ понимания словаря 9X_python-interpreter с проверкой отсутствующих значений с помощью 9X_pythonic трюка NaN != NaN, а также с тестированием тегов None.

9X_Сделать pandas DataFrame в dict и dropna_py

np.random.seed(2020) import perfplot def comp_notnull(df1): return {k1: {k:v for k,v in v1.items() if pd.notnull(v)} for k1, v1 in df1.to_dict().items()} def comp_NaNnotNaN_None(df1): return {k1: {k:v for k,v in v1.items() if v == v and v is not None} for k1, v1 in df1.to_dict().items()} def comp_dropna(df1): return {k: v.dropna().to_dict() for k,v in df1.items()} def comp_bool_indexing(df1): return {k: v[v.notna()].to_dict() for k,v in df1.items()} def make_df(n): df1 = pd.DataFrame(np.random.choice([1,2, np.nan], size=(n, 5)), columns=list('ABCDE')) return df1 perfplot.show( setup=make_df, kernels=[comp_dropna, comp_bool_indexing, comp_notnull, comp_NaNnotNaN_None], n_range=[10**k for k in range(1, 7)], logx=True, logy=True, equality_check=False, xlabel='len(df)') 

Другая 9X_python ситуация: если генерировать словари по строкам 9X_pythonista - получить список из огромного количества 9X_pythonic небольших словарей, тогда быстрее всего 9X_python-shell будет понимание списка с фильтрацией NaN 9X_pythonista и Nones:

9X_Сделать pandas DataFrame в dict и dropna_python-shell

np.random.seed(2020) import perfplot def comp_notnull1(df1): return [{k:v for k,v in m.items() if pd.notnull(v)} for m in df1.to_dict(orient='r')] def comp_NaNnotNaN_None1(df1): return [{k:v for k,v in m.items() if v == v and v is not None} for m in df1.to_dict(orient='r')] def comp_dropna1(df1): return [v.dropna().to_dict() for k,v in df1.T.items()] def comp_bool_indexing1(df1): return [v[v.notna()].to_dict() for k,v in df1.T.items()] def make_df(n): df1 = pd.DataFrame(np.random.choice([1,2, np.nan], size=(n, 5)), columns=list('ABCDE')) return df1 perfplot.show( setup=make_df, kernels=[comp_dropna1, comp_bool_indexing1, comp_notnull1, comp_NaNnotNaN_None1], n_range=[10**k for k in range(1, 7)], logx=True, logy=True, equality_check=False, xlabel='len(df)') 

17
0

Ответ #3

Ответ на вопрос: Сделать pandas DataFrame в dict и dropna

написать функцию, созданную to_dict из панд

import pandas as pd import numpy as np from pandas import compat def to_dict_dropna(self,data): return dict((k, v.dropna().to_dict()) for k, v in compat.iteritems(data)) raw_data={'A':{1:2,2:3,3:4},'B':{1:np.nan,2:44,3:np.nan}} data=pd.DataFrame(raw_data) dict=to_dict_dropna(data) 

и 9X_python-shell в результате вы получите то, что хотите:

>>> dict {'A': {1: 2, 2: 3, 3: 4}, 'B': {2: 44.0}} 

9
0

Ответ #4

Ответ на вопрос: Сделать pandas DataFrame в dict и dropna

у вас может быть свой собственный класс 9X_python сопоставления, в котором вы можете избавиться 9X_python-shell от NAN:

class NotNanDict(dict): @staticmethod def is_nan(v): if isinstance(v, dict): return False return np.isnan(v) def __new__(self, a): return {k: v for k, v in a if not self.is_nan(v)} data.to_dict(into=NotNanDict) 

Вывод:

{'A': {1: 2, 2: 3, 3: 4}, 'B': {2: 44.0}} 

Время (из ответа @jezrael):

9X_Сделать pandas DataFrame в dict и dropna_pythonic

для 9X_python-shell увеличения скорости вы можете использовать 9X_python-interpreter numba:

from numba import jit @jit def dropna(arr): return [(i + 1, n) for i, n in enumerate(arr) if not np.isnan(n)] class NotNanDict(dict): def __new__(self, a): return {k: dict(dropna(v.to_numpy())) for k, v in a} data.to_dict(orient='s', into=NotNanDict) 

вывод:

{'A': {1: 2, 2: 3, 3: 4}, 'B': {2: 44.0}} 

Время (из ответа @jezrael):

9X_Сделать pandas DataFrame в dict и dropna_pythonic

9
2

  • @RicksupportsMonica Да. Ты прав. Этот медле ...

Ответ #5

Ответ на вопрос: Сделать pandas DataFrame в dict и dropna

Есть много способов решить эту проблему. В 9X_pythonista зависимости от количества строк будут меняться 9X_pythonic самые быстрые методы. Поскольку производительность 9X_pd важна, я понимаю, что количество строк велико.

import pandas as pd import numpy as np # Create a dataframe with random data df = pd.DataFrame(np.random.randint(10, size=[1_000_000, 2]), columns=["A", "B"]) # Add some NaNs df.loc[df["A"]==1, "B"] = np.nan 

Самым 9X_python быстрым решением, которое я получил, является 9X_python-shell простое использование метода dropna и понимания 9X_pythonic словаря:

%time {col: df[col].dropna().to_dict() for col in df.columns} CPU times: user 528 ms, sys: 87.2 ms, total: 615 ms Wall time: 615 ms 

Что в 10 раз быстрее по сравнению с одним из предложенных 9X_python решений:

Теперь, если мы протестируем это 9X_python-interpreter с одним из предложенных решений, мы получим:

%time [{k:v for k,v in m.items() if pd.notnull(v)} for m in df.to_dict(orient='rows')] CPU times: user 5.49 s, sys: 205 ms, total: 5.7 s Wall time: 5.69 s 

Это 9X_python-interpreter также в 2 раза быстрее, чем другие варианты, например:

%time {k1: {k:v for k,v in v1.items() if v == v and v is not None} for k1, v1 in df.to_dict().items()} CPU times: user 900 ms, sys: 133 ms, total: 1.03 s Wall time: 1.03 s 

Идея 9X_python-shell состоит в том, чтобы всегда пытаться использовать 9X_py встроенные функции pandas или numpy, поскольку они 9X_python-interpreter быстрее, чем обычный Python.

6
0

Ответ #6

Ответ на вопрос: Сделать pandas DataFrame в dict и dropna

Вы можете использовать понимание слов и 9X_pandas цикл по столбцам

{col:df[col].dropna().to_dict() for col in df} 

5
0

Ответ #7

Ответ на вопрос: Сделать pandas DataFrame в dict и dropna

Попробуйте код ниже,

import numpy as np import pandas as pd raw_data = {'A': {1: 2, 2: 3, 3: 4}, 'B': {1: np.nan, 2: 44, 3: np.nan}} data = pd.DataFrame(raw_data) {col: data[col].dropna().to_dict() for col in data} 

Вывод

{'A': {1: 2, 2: 3, 3: 4}, 'B': {2: 44.0}} 

9X_pythonista

3
0

Ответ #8

Ответ на вопрос: Сделать pandas DataFrame в dict и dropna

Я написал функцию для решения этой проблемы, не 9X_python-shell переопределяя to_dict и не вызывая ее более 9X_pythonic одного раза. Подход состоит в том, чтобы 9X_pandas рекурсивно обрезать "листья" с помощью значения 9X_pythonic nan / None.

def trim_nan_leaf(tree): """For a tree of dict-like and list-like containers, prune None and NaN leaves. Particularly applicable for json-like dictionary objects """ # d may be a dictionary, iterable, or other (element) # * Do not recursively iterate if string # * element is the base case # * Only remove nan and None leaves def valid_leaf(leaf): if leaf is None: return(False) if isinstance(leaf, numbers.Number): if (not math.isnan(leaf)): return(leaf != -9223372036854775808) return(False) return(True) # Attempt dictionary try: return({k: trim_nan_leaf(tree[k]) for k in tree.keys() if valid_leaf(tree[k])}) except AttributeError: # Execute base case on string for simplicity... if isinstance(tree, str): return(tree) # Attempt iterator try: # Avoid infinite recursion for self-referential objects (like one-length strings!) if tree[0] == tree: return(tree) return([trim_nan_leaf(leaf) for leaf in tree if valid_leaf(leaf)]) # TypeError occurs when either [] or iterator are availble except TypeError: # Base Case return(tree) 

2
0

Ответ #9

Ответ на вопрос: Сделать pandas DataFrame в dict и dropna

улучшение ответа https://stackoverflow.com/a/46098323

С фреймом данных размером 9X_pythonic ~ 300 КБ с 2 полными столбцами nan, его 9X_pythonista ответ приводит:

%time [ {k:v for k,v in m.items() if pd.notnull(v)} for m in df.to_dict(orient='records')]
CPU times: user 8.63 s, sys: 137 ms, total: 8.77 s Wall time: 8.79 s

С небольшим поворотом:

%time [ {k:v for k,v in m.items()} for m in df.dropna(axis=1).to_dict(orient='records')]
CPU times: user 4.37 s, sys: 109 ms, total: 4.48 s Wall time: 4.49 s

Идея 9X_python-shell состоит в том, чтобы всегда сначала отбрасывать 9X_pd nan, чтобы избежать ненужных итераций по 9X_python-interpreter значению nan. При первом ответе nan сначала 9X_python-shell преобразуется в dict перед удалением, что 9X_pythonic можно оптимизировать.

2
0