8

So I have a df where I am extracting one value to store it in another df:

import pandas as pd

# Create data set
d = {'foo':[100, 111, 222], 
     'bar':[333, 444, 555]}
df = pd.DataFrame(d)

# Full dataframe:
print(df)

# Shows:
#    bar   foo 
# 0  333   100
# 1  444   111
# 2  555   222

df2=pd.DataFrame()
df2.loc[1,'Name'] = df[df.foo == 222]['foo']

#error: 
ValueError: Incompatible indexer with Series

I'm assuming the last line throws that error because df[df.foo == 222]['foo'] is a Series:

2    222
Name: foo, dtype: int64

So I'm trying to get the value itself. I used .at and got this:

print(df[df.foo == 222].loc[:,'bar'].at['bar'])

#ValueError: At based indexing on an integer index can only have integer indexers

From what I've read it's iat that uses integer indexers and at uses both label and integer, so what's going on here?

4 Answers 4

7

Using at with a boolean mask is considered bad form unless you can 100% guarantee only one row in the mask is true (otherwise, at fails).

The best thing to do is to use loc and take the first result.

df.loc[df.foo == 222, 'bar'].values[0]
555

For reference, at does not work because returns a single-row Series with a index [2]:

df[df.foo == 222].loc[:,'bar']

2    555
Name: bar, dtype: int64

At this point, at['bar'] makes no sense because it searches for "bar" in the index and bar isn't. What you should've done is

df[df.foo == 222].at[2, 'bar']
555
Sign up to request clarification or add additional context in comments.

4 Comments

@NathanTew Well, if you think about it; it makes sense. Pandas assumes you know what you are doing when you use these indexer functions, although I will admit there is a non-zero gradient to this learning curve.
but isn't untrue in itself to say that at only can have integer indexers, because it doesn't?
@NathanTew But df[df.foo == 222].loc[:,'bar'] does only have integer indices, so it will naturally complain when you try to index with a non-integer (.at['bar']).
@NathanTew (Last ping, promise) Thank you for accepting; you can also upvote the answer if it was helpful. Click the triangle above the "0" to the left of my answer. Thank you!
0

You can easily get the value using values

df2.loc[1,'Name'] = df[df.foo == 222]['foo'].values
df2

#   Name
# 1 222

2 Comments

thanks, that helped, but my main question was why .at isn't working
pass the complete index to at like at.[row_idx, col_idx]
0

The point at which you're using at, the data is a Pandas Series with integer Index, That is why your getting the mentioned error.

#ValueError: At based indexing on an integer index can only have integer indexers

If you check the index of the data, you'll see an index with value 2

df[df.foo == 222].loc[:,'bar'].index

#Int64Index([2], dtype='int64')

One of the correct method would be, as mentioned by coldspeed

df.loc[df.foo == 222].at[2,'bar']

#555

Comments

0

.at will work with label indexing, not position indexing.
Example:

df.at(3,'ColName')

Returns value of ColName for 3rd row.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.