Pandy Pythona wstawiają listę do komórki

106

Mam listę „abc” i ramkę danych „df”:

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

Chcę wstawić listę do komórki 1B, więc chcę ten wynik:

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

Jak mogę to zrobić?

1) Jeśli używam tego:

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

Otrzymuję następujący komunikat o błędzie:

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

ponieważ próbuje wstawić listę (która ma dwa elementy) do wiersza / kolumny, ale nie do komórki.

2) Jeśli używam tego:

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

następnie wstawia listę zawierającą tylko jeden element, którym jest lista „abc” ( [['foo', 'bar']]).

3) Jeśli używam tego:

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

następnie wstawia ciąg: ( foo, bar), ale nie listę.

4) Jeśli używam tego:

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

następnie wstawia listę, ale ma tylko jeden element ( ['foo, bar']), ale nie dwa, jak chcę ( ['foo', 'bar']).

Dzięki za pomoc!


EDYTOWAĆ

Moja nowa ramka danych i stara lista:

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

Inna ramka danych:

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

Chcę wstawić listę „abc” do df2.loc[1,'B']i / lub df3.loc[1,'B'].

Jeśli ramka danych zawiera kolumny tylko z wartościami całkowitymi i / lub wartościami NaN i / lub wartościami listy, to wstawienie listy do komórki działa idealnie. Jeśli ramka danych ma kolumny tylko z wartościami ciągów i / lub wartościami NaN i / lub wartościami listy, wstawienie listy do komórki działa idealnie. Ale jeśli ramka danych ma kolumny z wartościami całkowitymi i ciągami oraz inne kolumny, pojawi się komunikat o błędzie, jeśli użyję tego: df2.loc[1,'B'] = abclub df3.loc[1,'B'] = abc.

Inna ramka danych:

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

Te wkładki działają idealnie: df.loc[1,'B'] = abclub df4.loc[1,'B'] = abc.

ragesz
źródło
1
Jakiej wersji pandy używasz? następujące osoby pracowały przy użyciu pand 0.15.0:df.loc[1,'b'] = ['foo','bar']
EdChum
Dziękuję Ci! Używam Pythona 2.7 i wypróbowałem pandy 0.14.0 i 0.15.0 i działało z powyższymi danymi testowymi. Ale co, jeśli mam również kolumnę „C” z pewnymi wartościami całkowitymi? „A” ma struny. Mając kolumnę liczb całkowitych i kolumnę srting otrzymuję ten sam błąd: ValueError: Musi mieć równe klucze len i wartość podczas ustawiania za pomocą
iteracji
Będziesz musiał opublikować dane i kod, aby wyjaśnić i pokazać, co masz na myśli
EdChum

Odpowiedzi:

121

Ponieważ set_valuejest przestarzały od wersji 0.21.0, powinieneś teraz używać at. Może wstawić listę do komórki bez podnoszenia a ValueErrortak locjak. Myślę, że dzieje się tak, ponieważ at zawsze odnosi się do pojedynczej wartości, podczas gdy locmoże odnosić się zarówno do wartości, jak i wierszy i kolumn.

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

Musisz również upewnić się, że kolumna, do której wstawiasz, ma dtype=object. Na przykład

>>> 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
źródło
4
Musiałem się upewnić, że oryginalny dataframe dtype był ustawiony na sprzeciw, aby to zadziałało:df = pd.DataFrame(data, dtype=object)
Takver
2
w razie potrzeby indeks. Jak odwołać się do wiersza przy użyciu innego dopasowania wartości atrybutu; np .: dla wiersza z A = 2 w powyższym przykładzie?
bikashg
8
To zwraca kolejny błąd ValueError: setting an array element with a sequence.; zobacz odpowiedź @ cs95, jeśli pojawi się błąd.
Blaszard
39

df3.set_value(1, 'B', abc)działa dla dowolnej ramki danych. Zwróć uwagę na typ danych w kolumnie „B”. Na przykład. listy nie można wstawić do kolumny typu float, w takim przypadku df['B'] = df['B'].astype(object)może pomóc.

ragesz
źródło
6
Zauważ, że to polecenie jest przestarzałe . Poniżej znajduje się aktualizacja.
Thomas
35

Pandy> = 0,21

set_valuezostał wycofany. Możesz teraz używać DataFrame.atdo ustawiania według etykiety i DataFrame.iatdo ustawiania według pozycji całkowitej.

Ustawianie wartości komórek za pomocą 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

Jeśli chcesz ustawić wartość w drugim wierszu „B” na jakąś nową listę, użyj DataFrane.at:

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

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

Możesz również ustawić według pozycji całkowitej za pomocą DataFrame.iat

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

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

A co jeśli dostanę ValueError: setting an array element with a sequence?

Spróbuję to odtworzyć za pomocą:

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.

Dzieje się tak, ponieważ twój obiekt jest typu float64dtype, podczas gdy listy to objects, więc występuje tam niedopasowanie. W takiej sytuacji musisz najpierw przekonwertować kolumnę na obiekt.

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

A     int64
B    object
dtype: object

Wtedy działa:

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

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

Możliwe, ale Hacky

Co więcej, odkryłem, że możesz się włamać, DataFrame.locaby osiągnąć coś podobnego, jeśli przepuszczasz zagnieżdżone listy.

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

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

Możesz przeczytać więcej o tym, dlaczego to działa tutaj.

cs95
źródło
2

Szybka obejście

Po prostu umieść listę w nowej liście, tak jak to zrobiono dla col2 w ramce danych poniżej. Powodem tego jest to, że Python pobiera zewnętrzną listę (list) i konwertuje ją na kolumnę, tak jakby zawierała normalne elementy skalarne, którymi w naszym przypadku są listy, a nie zwykłe skalary.

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
źródło
0

Również dostaję

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

użycie .at zamiast .loc nie zrobiło żadnej różnicy w moim przypadku, ale wymuszenie typu danych kolumny dataframe załatwiło sprawę:

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

Następnie mógłbym ustawić listy, tablicę numpy i inne rzeczy jako wartości pojedynczych komórek w moich ramkach danych.

Maxime Beau
źródło