Les pandas python insèrent une liste dans une cellule

106

J'ai une liste 'abc' et un dataframe 'df':

abc = ['foo', 'bar']
df =
    A  B
0  12  NaN
1  23  NaN

Je veux insérer la liste dans la cellule 1B, donc je veux ce résultat:

    A  B
0  12  NaN
1  23  ['foo', 'bar']

Comment puis-je faire ça?

1) Si j'utilise ceci:

df.ix[1,'B'] = abc

Je reçois le message d'erreur suivant:

ValueError: Must have equal len keys and value when setting with an iterable

car il essaie d'insérer la liste (qui a deux éléments) dans une ligne / colonne mais pas dans une cellule.

2) Si j'utilise ceci:

df.ix[1,'B'] = [abc]

puis il insère une liste qui n'a qu'un seul élément qui est la liste 'abc' ( [['foo', 'bar']] ).

3) Si j'utilise ceci:

df.ix[1,'B'] = ', '.join(abc)

puis il insère une chaîne: ( foo, bar ) mais pas une liste.

4) Si j'utilise ceci:

df.ix[1,'B'] = [', '.join(abc)]

puis il insère une liste mais il n'a qu'un seul élément ( ['foo, bar']) mais pas deux comme je veux (['foo', 'bar'] ).

Merci pour l'aide!


ÉDITER

Mon nouveau dataframe et l'ancienne liste:

abc = ['foo', 'bar']
df2 =
    A    B         C
0  12  NaN      'bla'
1  23  NaN  'bla bla'

Un autre dataframe:

df3 =
    A    B         C                    D
0  12  NaN      'bla'  ['item1', 'item2']
1  23  NaN  'bla bla'        [11, 12, 13]

Je veux insérer la liste 'abc' dans df2.loc[1,'B']et / oudf3.loc[1,'B'] .

Si la trame de données contient des colonnes uniquement avec des valeurs entières et / ou des valeurs NaN et / ou des valeurs de liste, l'insertion d'une liste dans une cellule fonctionne parfaitement. Si le dataframe a des colonnes uniquement avec des valeurs de chaîne et / ou des valeurs NaN et / ou des valeurs de liste, l'insertion d'une liste dans une cellule fonctionne parfaitement. Mais si le dataframe a des colonnes avec des valeurs entières et de chaîne et d'autres colonnes, le message d'erreur apparaît si j'utilise ceci: df2.loc[1,'B'] = abcoudf3.loc[1,'B'] = abc .

Un autre dataframe:

df4 =
          A     B
0      'bla'  NaN
1  'bla bla'  NaN

Ces inserts fonctionnent parfaitement: df.loc[1,'B'] = abcou df4.loc[1,'B'] = abc.

ragesz
la source
1
Quelle version de pandas utilisez-vous? ce qui suit a fonctionné avec des pandas 0.15.0:df.loc[1,'b'] = ['foo','bar']
EdChum
Je vous remercie! J'utilise Python 2.7 et j'ai essayé les pandas 0.14.0 et 0.15.0 et cela a fonctionné avec les données de test ci-dessus. Mais que se passe-t-il si j'ai également une colonne «C» avec des valeurs entières? «A» a des chaînes. Ayant une colonne entière et une colonne srting, j'obtiens la même erreur: ValueError: Doit avoir des clés de len et une valeur égales lors du réglage avec un itérable
ragesz
Vous allez devoir publier des données et du code pour expliquer et montrer ce que vous voulez dire
EdChum

Réponses:

121

Comme il set_valueest obsolète depuis la version 0.21.0, vous devez maintenant utiliser at. Il peut insérer une liste dans une cellule sans lever un ValueErrorcomme le locfait. Je pense que c'est parce que fait at toujours référence à une seule valeur, alors que locpeut faire référence à des valeurs ainsi qu'à des lignes et des colonnes.

df = pd.DataFrame(data={'A': [1, 2, 3], 'B': ['x', 'y', 'z']})

df.at[1, 'B'] = ['m', 'n']

df =
    A   B
0   1   x
1   2   [m, n]
2   3   z

Vous devez également vous assurer que la colonne dans laquelle vous insérez a dtype=object. Par exemple

>>> df = pd.DataFrame(data={'A': [1, 2, 3], 'B': [1,2,3]})
>>> df.dtypes
A    int64
B    int64
dtype: object

>>> df.at[1, 'B'] = [1, 2, 3]
ValueError: setting an array element with a sequence

>>> df['B'] = df['B'].astype('object')
>>> df.at[1, 'B'] = [1, 2, 3]
>>> df
   A          B
0  1          1
1  2  [1, 2, 3]
2  3          3
Michael Hays
la source
4
Je devais m'assurer que le dtype du dataframe d'origine était défini sur object pour que cela fonctionne:df = pd.DataFrame(data, dtype=object)
Takver
2
at a besoin d'un index. Comment faire référence à la ligne en utilisant une autre correspondance de valeur d'attribut; par exemple: pour la ligne avec A = 2 dans l'exemple ci-dessus?
bikashg
8
Cela renvoie une autre erreur ValueError: setting an array element with a sequence.; voir une réponse par @ cs95 si vous obtenez l'erreur.
Blaszard
39

df3.set_value(1, 'B', abc)fonctionne pour n'importe quel dataframe. Prenez soin du type de données de la colonne «B». Par exemple. une liste ne peut pas être insérée dans une colonne flottante, dans ce cas df['B'] = df['B'].astype(object)peut aider.

ragesz
la source
6
Notez que cette commande est obsolète . Il y a une mise à jour juste en dessous.
Thomas
35

Pandas> = 0,21

set_valueest obsolète. Vous pouvez maintenant utiliser DataFrame.atpour définir par étiquette et DataFrame.iatpour définir par position entière.

Définition des valeurs de cellule avec at/iat

# Setup
df = pd.DataFrame({'A': [12, 23], 'B': [['a', 'b'], ['c', 'd']]})
df

    A       B
0  12  [a, b]
1  23  [c, d]

df.dtypes

A     int64
B    object
dtype: object

Si vous souhaitez définir une valeur dans la deuxième ligne du "B" pour une nouvelle liste, utilisez DataFrane.at:

df.at[1, 'B'] = ['m', 'n']
df

    A       B
0  12  [a, b]
1  23  [m, n]

Vous pouvez également définir par position entière en utilisant DataFrame.iat

df.iat[1, df.columns.get_loc('B')] = ['m', 'n']
df

    A       B
0  12  [a, b]
1  23  [m, n]

Et si j'obtiens ValueError: setting an array element with a sequence?

Je vais essayer de reproduire cela avec:

df

    A   B
0  12 NaN
1  23 NaN

df.dtypes

A      int64
B    float64
dtype: object

df.at[1, 'B'] = ['m', 'n']
# ValueError: setting an array element with a sequence.

C'est parce que votre objet est de float64 type d, alors que les listes sont des objects, il y a donc une incompatibilité. Dans cette situation, vous devez d'abord convertir la colonne en objet.

df['B'] = df['B'].astype(object)
df.dtypes

A     int64
B    object
dtype: object

Ensuite, ça marche:

df.at[1, 'B'] = ['m', 'n']
df

    A       B
0  12     NaN
1  23  [m, n]

Possible, mais Hacky

Encore plus farfelu, j'ai trouvé que vous pouvez pirater DataFrame.locpour obtenir quelque chose de similaire si vous passez des listes imbriquées.

df.loc[1, 'B'] = [['m'], ['n'], ['o'], ['p']]
df

    A             B
0  12        [a, b]
1  23  [m, n, o, p]

Vous pouvez en savoir plus sur les raisons pour lesquelles cela fonctionne ici.

cs95
la source
2

Travail rapide

Insérez simplement la liste dans une nouvelle liste, comme cela a été fait pour col2 dans le bloc de données ci-dessous. La raison pour laquelle cela fonctionne est que python prend la liste externe (des listes) et la convertit en une colonne comme si elle contenait des éléments scalaires normaux, qui sont des listes dans notre cas et non des scalaires normaux.

mydict={'col1':[1,2,3],'col2':[[1, 4], [2, 5], [3, 6]]}
data=pd.DataFrame(mydict)
data


   col1     col2
0   1       [1, 4]
1   2       [2, 5]
2   3       [3, 6]
Pallavi Jindal
la source
0

Obtention également

ValueError: Must have equal len keys and value when setting with an iterable,

l'utilisation de .at plutôt que de .loc n'a fait aucune différence dans mon cas, mais l'application du type de données de la colonne dataframe a fait l'affaire:

df['B'] = df['B'].astype(object)

Ensuite, je pourrais définir des listes, un tableau numpy et toutes sortes de choses en tant que valeurs de cellule unique dans mes dataframes.

Maxime Beau
la source