Имея этот фрейм данных

d = {'objects':[{'Sand':10},{'Seawater': 2, 'Crab': 30},{'Parasol': 50}]}
df = pd.DataFrame(data=d)

Я хочу эту пару ключ-значение

{'Small': 1000}

Быть вставленным в каждую строку, которая имеет по крайней мере пару ключ-значение со значением менее 40.

     objects
0    {'Sand': 10, 'Small': 1000}
1    {'Seawater': 2, 'Crab': 30, 'Small': 1000}
2    {'Parasol': 50}

Я пытался зацикливаться на этом, но это дает «Нет».

def your_small(x):
    if any(value < 40 for value in x.values()):
        return x.update({'Small': 1000})

d = {'objects':[{'Sand':10},{'Seawater': 2, 'Crab': 30},{'Parasol': 50}]}
df = pd.DataFrame(data=d)
df['objects'] = df['objects'].map(your_small)
  objects
0    None
1    None
2    None
2
Masaki Andou 20 Дек 2019 в 19:03

2 ответа

Лучший ответ

Как сказал @ALoll, вы можете пересмотреть свой подход.

Если вы хотите, чтобы ваш существующий код работал, вам нужно подумать о том, как работает карта: вы должны вернуть значение в функцию карты. x.update возвращает None, и вы должны вернуть x как есть, если ваши условия не выполняются:

def your_small(x):
    if any(value < 40 for value in x.values()):
        return {**x, 'Small': 1000}
    return x
3
Pierre V. 20 Дек 2019 в 16:14

Если диктовки на самом деле не нужны, вот способ с MultiIndex. Здесь я буду предполагать, что отдельные dicts имеют в основном неперекрывающиеся ключи, поэтому длинный DataFrame кажется более подходящим. (Широкий DataFrame может быть лучше, если большинство диктов имеют перекрывающиеся ключи)

import pandas as pd

df = pd.concat([pd.DataFrame.from_dict(di, orient='index', columns=['N']) for di in d['objects']], 
               keys=range(len(d['objects'])))
#             N
#0 Sand      10
#1 Seawater   2
#  Crab      30
#2 Parasol   50

# Determine which original "rows" have at least one value < 40
s = df.N.lt(40).groupby(level=0).any()

df_add = pd.DataFrame({'N': 1000},
                      index = pd.MultiIndex.from_product([s[s].index, ['Small']]))

# Join them:
df = pd.concat([df, df_add]).sort_index()
#               N
#0 Sand        10
#  Small     1000
#1 Crab        30
#  Seawater     2
#  Small     1000
#2 Parasol     50

Вот версия с широким DataFrame. Намного легче манипулировать, но может стать очень большим.

df = pd.DataFrame.from_records(d['objects'])
#   Sand  Seawater  Crab  Parasol
#0  10.0       NaN   NaN      NaN
#1   NaN       2.0  30.0      NaN
#2   NaN       NaN   NaN     50.0

df.loc[df.lt(40).any(1), 'Small'] = 1000
#   Sand  Seawater  Crab  Parasol   Small
#0  10.0       NaN   NaN      NaN  1000.0
#1   NaN       2.0  30.0      NaN  1000.0
#2   NaN       NaN   NaN     50.0     NaN
2
ALollz 20 Дек 2019 в 16:57
59428164