LoginSignup
0
0

pandas クイズ

Last updated at Posted at 2024-04-22
1 / 60

はじめに


概要

pandasを使っていたハマったことや、ハマりそうなことをクイズにしました。

問題の多くは2択です。直観で答えてみてください。

2024/04/19に社内でpandasクイズを実施しました。


動作環境

以下の環境で動作確認しました。

  • pandas 2.2.2
  • numpy 1.26.4
  • Python 3.12.1

事前にIPythonで以下をimportしています。

In [1]: import pandas as pd
In [2]: import numpy as np

問題文の例(出力結果を答える)

IPythonで実行したときに、どのような結果になるかを選択してください。
問題となる実行文は、In [?]で表します。
出力結果の選択肢はOut[1], Out[2]のように表します。

In [?]: np.inf - np.inf

Out[1]: nan

Out[2]: 0.0

Out[3]: 
raise Error

1, 2, 3のいずれかの番号を選択してください。

なお、回答は1です。


問題文の例(実行文を答える)

ある実行文に対する出力結果をOut[?]で表します。
ある実行文の選択肢を、In[1], In[2]のように表します。

In [1]: np.inf + np.inf

In [2]: np.inf - np.inf

In [3]: np.inf * np.inf

In [4]: np.inf / np.inf

Out[?]: nan

適切な実行文を1, 2, 3, 4の番号からすべてを選択してください。

なお、回答は2と4です。


データの取得に関するクイズ


問01: Seriesに対して[]でアクセス

In [372]: s1 = pd.Series(["a","b"])

In [373]: s1
Out[373]:
0    a
1    b
dtype: object

# `[0]`は0番目の要素が返る
In [374]: s1[0]
Out[374]: 'a'

ですが...

# indexがs1と異なる場合
In [375]: s2 = pd.Series(["a","b"], index=[1,0])

In [376]: s2
Out[376]:
1    a
0    b
dtype: object

In [?]: s2[0]

# 0番目の要素が返る?
Out[1]: 'a'

# indexが0である要素が返る?
Out[2]: 'b'

適切なOuputを1つ選択してください。


答: 2

indexが0である要素が返ります。

In [377]: s2[0]
Out[377]: 'b'

問02: Seriesに対して[]でアクセス Part2

In [559]: s3 = pd.Series(["a","b"], index=["x","y"])

In [560]: s3
Out[560]:
x    a
y    b
dtype: object

In [?]: s3[0]

# 0番目の要素が返る?
Out[1]: 'a'

# indexに0は存在しないからエラーが発生する?
Out[2]:
raise KeyError

適切なOutputを1つ選択してください。


答: 1

0番目の要素が返ります。
ただしFutureWarningが発生します。将来のバージョンではindexが0である要素を返すようなので、エラーが発生すると思います。

In [561]: s3[0]
<ipython-input-561-e48481fcb92e>:1: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`
  s3[0]

問03: Seriesに対して.loc[]にスライスを指定したとき

In [391]: s1 = pd.Series([4,5,6], index=["a","b","c"])

In [?]: s1.loc["a":"b"]
# index "b"は含まれる?
Out[1]:
a    4
b    5
dtype: int64

# index "b"は含まれない?
Out[2]:
a    4
dtype: int64

答: 1

スライスの終了位置は含まれます。

In [412]: s1.loc["a":"b"]
Out[412]:
a    4
b    5
dtype: int64

問04: Seriesに対して.loc[]にスライスを指定する Part2

# indexに整数を指定
In [417]: s1 = pd.Series(["a","b","c"], index=[1,3,5])

In [418]: s1.loc[1:5]
Out[418]:
1    a
3    b
5    c
dtype: object
# indexに存在しない0を開始,6は終了に指定する
In [?]: s1.loc[0:6]
Out[1]:
1    a
3    b
5    c
dtype: object

Out[2]:
raise KeyError

適切なOutputを1つ選択してください。


答: 1

If at least one of the two is absent, but the index is sorted, and can be compared against start and stop labels, then slicing will still work as expected, by selecting labels which rank between the two 1

※ "at least one of the two is absent"とあるが、両方存在しなくても期待通り動くのはなぜ?

# indexがソートされていない場合
In [445]: s = pd.Series(["a","b","c"], index=[5,1,3])

In [446]: s.loc[0:6]
...
KeyError: 0

However, if at least one of the two is absent and the index is not sorted, an error will be raised (since doing otherwise would be computationally expensive, as well as potentially ambiguous for mixed type indexes). 2


問05: Seriesに対して[]にスライスを指定する

In [391]: s1 = pd.Series([4,5,6], index=["a","b","c"])

In [400]: s1
Out[400]:
a    4
b    5
c    6
dtype: int64

In [?]: s1[1:]

# indexに1は存在しないからエラーになる?
Out[1]:
raise KeyError

# 1番目以降の要素が返る?
Out[2]:
b    5
c    6
dtype: int64

適切なOutputを一つ選択してください。


答: 2

[1:]は、1番目以降の要素が返ります。

In [402]: s1[1:]
Out[402]:
b    5
c    6
dtype: int64

なお、スライスでindexを指定することもできます。

In [471]: s1["b":]
Out[471]:
b    5
c    6
dtype: int64

Seriesに対して[]を指定したときの挙動は、__getitem__()で定義されています。

__getitem__()の中では、以下のような判定を行って処理しています。

  • key_is_scalar -> self._get_value(key)
  • is_integer(key) and self.index._should_fallback_to_positional -> self._values[key]
  • isinstance(key, slice) -> self._getitem_slice(key)

問06: DataFrameに対して[]でアクセスする

# columnとindexを同じにする
In [451]: df = pd.DataFrame({"a":[1,2], "b":[3,4]}, index=["a","b"])

In [452]: df
Out[452]:
   a  b
a  1  3
b  2  4

In [?]: df["a"]
# column "a"が返る?
Out[1]:
a    1
b    2
Name: a, dtype: int64

# index "a"が返る?
Out[2]:
a    1
b    3
Name: a, dtype: int64

適切なOutputを1つ選択してください。


答: 1

column aの情報が返ります。


In [473]: df["a"]
Out[473]:
a    1
b    2
Name: a, dtype: int64

問07: DataFrameに対して[]にスライスを指定する

In [451]: df = pd.DataFrame({"a":[1,2], "b":[3,4]}, index=["a","b"])

In [452]: df
Out[452]:
   a  b
a  1  3
b  2  4

In [?]: df["b":]
# column "b"の情報が返る?
Out[1]:
   b
a  3
b  4

# index "b"の情報が返る?
Out[2]:
   a  b
b  2  4

適切なOutputを1つ選択してください。


答: 2

DataFrameに対して[]にスライスを指定すると、indexに紐づく情報が返ります。

In [474]: df["b":]
Out[474]:
   a  b
b  2  4

問08: Seriesをfor inでループする

In [460]: s = pd.Series([1,2], index=["a","b"])

In [461]: s
Out[461]:
a    1
b    2
dtype: int64

In [?]: [e for e in s]

# 値が返る? list-like?
Out[1]: [1, 2]

# indexが返る? dict-like?
Out[2]: ["a", "b"]

適切なOutputを1つ選択してください。


答: 1

Seriesをfor-inループで回すと値が返ります。

In [467]:  [e for e in s]
Out[467]: [1, 2]

Seriesはdict-likeでもありlist-likeです。


Seriesオブジェクトの生成に関するクイズ


問11: Series()index引数を指定した場合

# 事前知識
In [15]: pd.Series(data={"a":1.0, "b":2.0})
Out[15]:
a    1.0
b    2.0
dtype: float64
In [?]: pd.Series(data={"a":1.0, "b":2.0}, index=["a","c"])

# `index`優先
Out[1]:
a    1.0
c    NaN
dtype: float64

# `data`優先
Out[2]:
a    1.0
b    2.0
dtype: float64

# `data`と`index`のunion
Out[3]:
a    1.0
b    2.0
c    NaN
dtype: float64

適切なOutputを選択してください。


答: 1

In [475]: pd.Series(data={"a":1.0, "b":2.0}, index=["a","c"])
Out[475]:
a    1.0
c    NaN
dtype: float64

If an index is passed, the values in data corresponding to the labels in the index will be pulled out. 3


問12: Series()index引数を指定した場合 Part2

In [19]: pd.Series([1.0, 2.0], index=["a", "b"])
Out[19]:
a    1.0
b    2.0
dtype: float64
# dataのlengthとindexの長さ異なる場合
In [?]: pd.Series([1.0, 2.0], index=["a"])

Out[1]:
a    1.0
dtype: float64

Out[2]: 
raise ValueError

適切なOutputを選択してください。


答: 2

In [475]: pd.Series(data={"a":1.0, "b":2.0}, index=["a","c"])
Out[475]:
a    1.0
c    NaN
dtype: float64

In [476]: pd.Series([1.0, 2.0], index=["a"])
--------------------------------------------------------------
ValueError: Length of values (2) does not match length of index (1)

If data is an ndarray, index must be the same length as data. 4

index引数で指定した値が優先される訳ではないようです。


問13: Series同士の加算

In [475]: s = pd.Series([1,2], index=["a","b"])

In [480]: s1 = s.iloc[0:1]

In [481]: s1
Out[481]:
a    1
dtype: int64

In [482]: s2 = s.iloc[1:]

In [483]: s2
Out[483]:
b    2
dtype: int64

In [?]: s1 + s2

# 同じindexのものがあれば加算されるが、同じindexはないのでindexをunionしたものと同じになる?
Out[1]:
a   1
b   2
dtype: int64

# 同じindexのもの同士で加算するが、同じindexがないのでNaNとの加算になる?
Out[2]:
a   NaN
b   NaN
dtype: float64

# 両方に存在するindexは存在しないから、空のSereisになる?
Out[3]: Series([], dtype: float64)

適切なOutputを選択してください。


答: 2

In [486]: s1 + s2
Out[486]:
a   NaN
b   NaN
dtype: float64

The result of an operation between unaligned Series will have the union of the indexes involved. If a label is not found in one Series or the other, the result will be marked as missing NaN. 5


DataFrameオブジェクトの生成に関するクイズ


問21: 異なるnamedtupleで構成されたlistをpd.DataFrame()に渡す

In [32]: from collections import namedtuple
In [33]: Point = namedtuple("Point", "x y")
In [34]: Point3D = namedtuple("Point3D", "x y z")
# 先頭の要素が`Point3D`
In [?]: pd.DataFrame([Point3D(0, 0, 0),  Point(0, 0)])
Out[1]:
   x  y    z
0  0  0  0.0
1  0  0  NaN

Out[2]:
raise ValueError
# 先頭の要素が`Point`
In [?]: pd.DataFrame([Point(0, 0), Point3D(0, 0, 0)])
Out[3]:
   x  y    z
0  0  0  NaN
1  0  0  0.0

Out[4]:
raise ValueError

適切なOutputをすべて選択してください。


答: 1, 4

In [490]: pd.DataFrame([Point3D(0, 0, 0),  Point(0, 0)])
Out[490]:
   x  y    z
0  0  0  0.0
1  0  0  NaN


In [38]: pd.DataFrame([Point(0, 0), Point3D(0, 0, 0)])
----
ValueError: 2 columns passed, passed data had 3 columns

The field names of the first namedtuple in the list determine the columns of the DataFrame. The remaining namedtuples (or tuples) are simply unpacked and their values are fed into the rows of the DataFrame. If any of those tuples is shorter than the first namedtuple then the later columns in the corresponding row are marked as missing values. If any are longer than the first namedtuple, a ValueError is raised. 6

dictのlistを渡せばValueErrorは発生しません。

In [10]: pd.DataFrame([{"x":0, "y":0}, {"x":0, "y":0, "z":0}])
Out[10]:
   x  y    z
0  0  0  NaN
1  0  0  0.0

問22: DataFrameに対してSeriesを代入して列を追加

In [17]: df = pd.DataFrame({"x":[1.0,2.0]}, index=["a","b"])

In [18]: df
Out[18]:
     x
a  1.0
b  2.0

In [19]: s = pd.Series([11.0, 13.0], index=["a","c"])

In [20]: s
Out[20]:
a    11.0
c    13.0
dtype: float64

# column 'y'を追加
In [21]: df["y"] = s

In [?]: df

# `df.index`と`s.index`のunionが新しいindexになる
Out[1]:
     x      y
a    1   11.0
b    2    NaN
c  NaN   13.0

# `df`に存在しないindexは無視される
Out[2]:
     x     y
a  1.0  11.0
b  2.0   NaN

適切なOutputを1つ選択してください。


答: 2

In [532]: s = pd.Series([11.0, 13.0], index=["a","c"])

In [533]: df = pd.DataFrame({"x":[1.0,2.0]}, index=["a","b"])

In [534]: df["y"] = s

In [535]: df
Out[535]:
     x     y
a  1.0  11.0
b  2.0   NaN

When inserting a Series that does not have the same index as the DataFrame, it will be conformed to the DataFrame’s index: 7

DataFrameへの代入で、DataFrameのindexは変化しない(はず)ようにみえます。


問23: DataFrameに対してlistを代入して列を追加

In [29]: df = pd.DataFrame({"x":[1.0,2.0]}, index=["a","b"])

In [30]: df
Out[30]:
     x
a  1.0
b  2.0

# column 'y' を追加
In [31]: df["y"] = [11.0, 12.0]

In [?]: df["y"]

# listにはindexが存在しないから、df.indexに対応しないのでY列はNaN ?
Out[1]:
a    NaN
b    NaN
Name: y, dtype: float64

# よしなに追加できるはず?
Out[2]:
a    11.0
b    12.0
Name: y, dtype: float64

適切なOutputを1つ選択してください。


答: 2

In [536]: df = pd.DataFrame({"x":[1.0,2.0]}, index=["a","b"])

In [537]: df["y"] = [11.0, 12.0]

In [538]: df["y"]
Out[538]:
a    11.0
b    12.0
Name: y, dtype: float64

問24: DataFrameに対してSeriesを代入して列を追加 Part2

In [29]: df = pd.DataFrame({"x":[1.0,2.0]}, index=["a","b"])

In [30]: df
Out[30]:
     x
a  1.0
b  2.0


In [30]: s = pd.Series([11.0, 12.0])

In [31]: s
Out[31]:
0    11.0
1    12.0
dtype: float64

# column 'y'を追加
In [32]: df["y"] = s

In [?]: df["y"]

# Seriesのindexはdf.indexに対応しないのでY列はNaN?
Out[1]:
a   NaN
b   NaN
Name: y, dtype: float64

# よしなに追加できるはず?
Out[2]:
a    11.0
b    12.0
Name: y, dtype: float64

適切なOutputを1つ選択してください。


答: 1

In [544]: df = pd.DataFrame({"x":[1.0,2.0]}, index=["a","b"])

In [546]: s = pd.Series([11.0, 12.0])

In [547]: df["y"] = s

In [548]: df["y"]
Out[548]:
a   NaN
b   NaN
Name: y, dtype: float64

問25: DataFrameSeriesの加算

In [41]: df = pd.DataFrame([[1,2],[3,4]])

In [42]: df
Out[42]:
   0  1
0  1  2
1  3  4

In [43]: s = pd.Series([10,20])

In [44]: s
Out[44]:
0    10
1    20
dtype: int64


In [?]: df + s

# 加算結果は、SeriesのindexとDataFrameのcolumnが対応している?
Out[1]:
    0   1
0  11  22
1  13  24

# 加算結果は、SeriesのindexとDataFrameのindexが対応している?
Out[2]:
    0   1
0  11  12
1  23  24

適切なOutputを1つ選択してください。


答: 1

加算結果は、SeriesのindexとDataFrameのcolumnが対応しています。

In [502]: df + s
Out[502]:
    0   1
0  11  22
1  13  24

When doing an operation between DataFrame and Series, the default behavior is to align the Series index on the DataFrame columns, thus broadcasting row-wise. 8:

add()メソッドのaxis引数を指定すれば、SeriesのindexをDataFrameのindexに対応させることもできます。

In [51]: df.add(s, axis="index")
Out[51]:
    0   1
0  11  12
1  23  24

比較演算に関するクイズ


問31: ==によるSeriesの比較

In [100]: s = pd.Series(["foo", "bar"])

In [101]: s
Out[101]:
0    foo
1    bar
dtype: object

# スカラー値との比較
In [1]: s == "foo"

# listとの比較
In [2]: s == ["foo", "bar"]

# numpy arrayとの比較
In [3]: s == np.array(["foo", "bar"])

# 長さの異なるpd.Seriesとの比較
In [4]: s == pd.Series(["foo"])

Errorが発生するInputはすべて選択してください。


答: 4のみ

In [1]: s == "foo"
Out[1]:
0     True
1    False
dtype: bool

In [2]: s == ["foo", "bar"]
Out[2]:
0    True
1    True
dtype: bool

In [3]: s == np.array(["foo", "bar"])
Out[3]:
0    True
1    True
dtype: bool

In [4]: s == pd.Series(["foo"])
---------------------------------------------------------------------------
...
ValueError: Can only compare identically-labeled Series objects

スカラー値やarray-likeなオブジェクトと比較できます。ただし、比較する際は長さを一致させる必要があります。9


問32: ==によるSeriesの比較 Part2

In [203]: s = pd.Series([1.0, np.nan])

In [204]: s
Out[204]:
0    1.0
1    NaN
dtype: float64

In [?]: s == s

Out[1]: True

Out[2]: False

Out[3]: 
0     True
1     True
dtype: bool

Out[4]:
0     True
1    False
dtype: bool

適切なOutputを一つ選択してください。


答: 4

要素同士を比較した結果(bool)のSeriesが返ります。ただしnp.nan == np.nanはFalseが返ることに注意してください。

In [207]: s == s
Out[207]:
0     True
1    False
dtype: bool

In [208]: np.nan == np.nan
Out[208]: False

同じ要素を持っているかどうかはequals()で確認できます。10

In [210]: s.equals(s)
Out[210]: True

問33: Seriesに対するin演算子の結果

In [222]: s = pd.Series([0,1], index=["a","b"])

In [223]: s
Out[223]:
a    0
b    1
dtype: int64

# index "a"が含まれているかを確認できる?
In [1]: "a" in s

# value "0"が含まれているかを確認できる?
In [2]: 0 in s

Out[?]: True

適切なInputを一つ選んでください。


答: 1

Using the Python in operator on a Series tests for membership in the index, not membership among the values.
If this behavior is surprising, keep in mind that using in on a Python dictionary tests keys, not values, and Series are dict-like. 1

In [227]: "a" in s
Out[227]: True

In [242]: 0 in s
Out[242]: False

# dictでも確認する
In [228]: d = {"a":1,"b":2}

In [229]: "a" in d
Out[229]: True

値が含まれているかはSeries.isin()で確認できます。

In [233]: s.isin([0])
Out[233]:
a     True
b    False
dtype: bool

問34: DataFrameに対するin演算子の結果

In [237]: df = pd.DataFrame({"a":[1,2], "b":[3,4]}, index=["x","y"])

In [238]: df
Out[238]:
   a  b
x  1  3
y  2  4

# index "x"が含まれているかを確認できる?
In [1]: "x" in df

# column "a"が含まれているかを確認できる?
In [2]: "a" in df

# value "1"が含まれているかを確認できる?
In [3]: 1 in df

Out[*]: True

適切なInputを一つ選んでください。


答: 2

In [239]: "x" in df
Out[239]: False

In [240]: "a" in df
Out[240]: True

In [241]: 1 in df
Out[241]: False

その他のクイズ


問41: 欠損値を含むデータのsum

In [1]: np.sum([1, 2, np.nan])

In [2]: pd.Series([1, 2, np.nan]).sum()
 
In [3]: np.sum(pd.Series([1, 2, np.nan]))

Out[*]: 3.0

適切なInputをすべて選んでください。


答: 2,3

Series.sum()などpandasのdescriptive statisticsなメソッドは、デフォルトでは欠損値を無視します。

In [1]: np.sum([1, 2, np.nan])
Out[1]: nan

In [2]: pd.Series([1, 2, np.nan]).sum()
Out[2]: 3.0
 
In [3]: np.sum(pd.Series([1,2,np.nan]))
Out[3]: 3.0

skipna=Falseを指定すれば、欠損値は無視されず、結果はnp.nanになります。

In [553]: pd.Series([1, 2, np.nan]).sum(skipna=False)
Out[553]: nan

np.sum(pd.Series([1,2,np.nan]))の結果がnp.nanでなく3.0である原因は分かりませんでした。

Note that by chance some NumPy methods, like mean, std, and sum, will exclude NAs on Series input by default 11


問42: 分散を求める

# numpyで分散を求める
In [?]: np.array([0]).var()

Out[1]: 0.0

Out[2]: nan

# pandasで分散を求める
In [?]: pd.Series([0]).var()

Out[3]: 0.0

Out[4]: nan

適切なOutputを複数選択してください。


答: 1, 4

numpyのvar()ではddof(自由度)引数のデフォルト値は0なのに対して、pandasのvar()ではデフォルト値は1です。

In [570]: np.array([0]).var()
Out[570]: 0.0

In [572]: pd.Series([0]).var()
Out[572]: nan

In [574]: pd.Series([0]).var(ddof=0)
Out[574]: 0.0


問43: agg()np.varを渡す

agg()には集約したい関数や関数名を渡すことができます。

In [6]: pd.Series([1,2]).agg(["sum"])
Out[6]:
sum    3
dtype: int64
In [?]: pd.Series([0]).agg([np.var])

Out[1]:
var   0.0
dtype: float64

Out[2]:
var   NaN
dtype: float64

適切なOutputを選択してください。


答: 2

np.varを実行しているように見えますが、実はpandasのvar()が呼ばれています。ただし、この挙動は将来のバージョンで変わります。

In [3]: pd.Series([0]).agg([np.var])
<ipython-input-3-bcf21703d287>:1: FutureWarning: The provided callable <function var at 0x7f71fa7d4c20> is currently using Series.var. In a future version of pandas, the provided callable will be used directly. To keep current behavior pass the string "var" instead.
  pd.Series([0]).agg([np.var])

まとめ


教訓

  • Seriesはlist-likeでもありdict-likeであることを意識する
  • Seriesを扱うときはindexを意識する
  • SeriesまたDataFrameに対して[]でアクセスすると、直観的でない挙動に遭遇するかもしれない。できるだけ.loc[].iloc[]を使った方がよい
  1. https://pandas.pydata.org/docs/user_guide/indexing.html#slicing-with-labels 2

  2. https://pandas.pydata.org/docs/user_guide/indexing.html#slicing-with-labels

  3. https://pandas.pydata.org/docs/user_guide/dsintro.html#series-is-dict-like

  4. https://pandas.pydata.org/docs/user_guide/dsintro.html#series

  5. https://pandas.pydata.org/docs/user_guide/dsintro.html#vectorized-operations-and-label-alignment-with-series

  6. https://pandas.pydata.org/docs/user_guide/dsintro.html#from-a-list-of-namedtuples

  7. https://pandas.pydata.org/docs/user_guide/dsintro.html#column-selection-addition-deletion

  8. https://pandas.pydata.org/docs/user_guide/dsintro.html#indexing-selection

  9. https://pandas.pydata.org/docs/user_guide/basics.html#comparing-array-like-objects

  10. https://pandas.pydata.org/docs/user_guide/basics.html#comparing-if-objects-are-equivalent

  11. https://pandas.pydata.org/docs/user_guide/basics.html#descriptive-statistics

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0