pandas中的那些让人有点懵逼的异常(坑向)
楔子
pandas是一個很強大的庫,但是在使用的過程中難免會遇見各種奇葩的異常,而這些異常卻又很難讓人定位到底是哪一步出了問題。下面就來看看pandas中的一些令人感到費解的異常吧,看看你有沒有遇到過,如果沒有的話,那么說明你pandas可能用的不夠多哦。
ヽ( ̄ω ̄( ̄ω ̄〃)ゝ一起來看看
1. SettingWithCopyWarning:
當然這不是個異常,而是一個警告,這個警告相信大多數人都遇到過,尤其是初學pandas的時候。這個警告具體內容如下:
SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead
See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/......
我們來復現一下這個警告:
import pandas as pd
df = pd.DataFrame({"name": ["mashiro", "koishi", "satori", "kurisu"],
"age": [17, 16, 17, 19],
"adult": [None, None, None, None]})
print(df)
"""
name age adult
0 mashiro 17 None
1 koishi 16 None
2 satori 17 None
3 kurisu 19 None
"""
# 我現在想將df中age > 18對應的audit設置為True
# 但是會發現沒有效果,并且SettingWithCopyWarning就是由這一行代碼引發的
df[df["age"] > 16]["adult"] = True
print(df)
"""
name age adult
0 mashiro 17 None
1 koishi 16 None
2 satori 17 None
3 kurisu 19 None
"""
為什么會出現這個原因呢?因為df[df["age"] > 16]得到的是原始DataFrame的一份拷貝,因此其相應的操作不會影響原來的DataFrame。盡管這樣的操作是允許的,但是卻無法得到正確的結果,因此pandas彈出了一個警告。
# 真正的做法是使用loc或者iloc
df.loc[df["age"] > 18, "adult"] = True
print(df)
"""
name age adult
0 mashiro 17 None
1 koishi 16 None
2 satori 17 None
3 kurisu 19 None
"""
2. TypeError: 'Series' objects are mutable, thus they cannot be hashed
這個異常實際上比較常見了,說白了就是你不小心把loc或者iloc給丟掉了,我們還用上面的例子
try:
df[df["age"] > 18, "adult"] = True
except Exception as e:
print(e) # 'Series' objects are mutable, thus they cannot be hashed
3. ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all()
我們知道,像if a:,not a之類的,本質上都是調用a的__bool__方法,可以理解為bool(a)
class A:
def __bool__(self):
return True
if A():
print("123")
else:
print("456")
print(bool(A()))
"""
123
True
"""
# 由于A的__bool__返回了True, 所以bool(A())為True
# 我們將其改為False
A.__bool__ = lambda self: False
print(bool(A())) # False
但是對于一個Series或者numpy中的array不可以這么做。
import pandas as pd
s = pd.Series([True, False])
try:
bool(s)
except Exception as e:
print(e) # The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
try:
if s.values: # 得到一個numpy中的array
pass
except Exception as e:
print(e) # The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
"""
對于一個Series對象來說,不可以使用其布爾值,應當使用 s.all()、s.any()或者np.all(s)、np.any(s)
但是對于numpy中的array來講,如果這個array里面的元素不止一個,那么也不可以使用其布爾值,但如果該array中只有一個元素的話是個例外
此時:if np.array([123]) 等價于 if 123
因此如果使用其布爾值的話,最好使用np.all()或者np.any()將一個序列變成單個布爾值
"""
# 但如果只是希望像列表一樣,如果該Series對象里面有值就是真,否則就是假
# 那么建議通過 if len(s):這種方式來判斷
# 同理DataFrame也是如此
4. 布爾你咋啦?
我們知道,可以對兩個類型為bool的Series對象進行 與、或、非 等操作,但是結果真的一定是我們想要的嗎?
import pandas as pd
s1 = pd.Series([True, True, True])
s2 = pd.Series([True, False, True], index=[1, 2, 3])
print(s1 & s2)
"""
0 False
1 True
2 False
3 False
dtype: bool
"""
# 我們看到與運算之后,長度變成了4,究其原因就是兩個Series索引不同造成的
# 而Series的很多操作都是基于索引進行對齊的,并不是簡簡單單地按照順序
# 但如果對應的索引一樣的話,那么也可以認為就是按照順序從上到下
# 但如果索引不一樣的話,pandas是怎么做的呢?答案是使用reindex
# 首先找到兩個Series對象中出現的所有不重復索引
index = s1.index | s2.index
print(index) # Int64Index([0, 1, 2, 3], dtype='int64')
# 使用reindex進行對齊, 不存在的使用NaN代替,當然我們也可以指定fill_value進行填充
# 比如fill_value=False
print(s1.reindex(index))
"""
0 True
1 True
2 True
3 NaN
dtype: object
"""
print(s2.reindex(index))
"""
0 NaN
1 True
2 False
3 True
dtype: object
"""
# 所以s1 & s2最終等價于 s1.reindex(index) & s2.reindex(index)
# 因此即使兩者個數不同也是沒有問題的
s1 = pd.Series([True, True, True, True])
s2 = pd.Series([True, True, True], index=[1, 2, 3])
print(s1 & s2)
"""
0 False
1 True
2 True
3 True
dtype: bool
"""
總之pandas中很多操作,并不是我們想的那么簡單,pandas的Series和DataFrame都具備索引的概念,通過索引來定位速度是非常快的。但是不注意就會造成陷阱,究其原因就是很多操作在定位的時候是基于索引來定位的,并不是簡單的按照順序。比如:s1 & s2,指的是s1和s2中相同索引對應的元素進行與運算,當然如果有對應不上的,事先已經通過reindex處理好了。
當然,如果我們不希望考慮索引的話,只是單純的希望按照順序進行位運算,該怎么做呢?辦法有兩種
import pandas as pd
s1 = pd.Series([True, True, True])
s2 = pd.Series([True, False, True], index=[1, 2, 3])
# 對Series使用reset_index即可,當然要指定drop=True,否則就變成DataFrame了
# 一旦reset_index之后兩者索引從頭到尾就是一致的了
print(s1.reset_index(drop=True) & s2.reset_index(drop=True))
"""
0 True
1 False
2 True
dtype: bool
"""
# 或者轉成numpy中的array
# 我們知道Series等價于numpy中的n個array,分別存放索引、值等等
# 我們調用s.index即可拿到索引,s.values即可拿到值
print(s1.values & s2)
"""
1 True
2 False
3 True
dtype: bool
"""
# 如果其中是一個array的話,那么它沒有索引的概念,索引此時也是單純的一個一個對應進行運算
# 當然得到的結果也是一個Series,索引和運算的Series的索引保持一致
# 或者都轉成array
print(s1.values & s2.values) # [ True False True]
# 但是注意:如果其中一方轉成了array,那么此時就要求兩個序列的布爾元素個數是必須相等的
# 此時就不會再通過reindex進行擴展了,因為array沒有reindex
# 當然都轉成array就更不用說了
我們說了很多關于索引的話題,之所以強調這一點,是因為這里面存在一個坑點。我們知道對于DataFrame對象來說,通過df[xxx]可以取得相應的數據,xxx的身份不同,取得的數據也不同
如果xxx是一個標量, 那么df[xxx]表示獲取df的某一列,得到一個Series對象
如果xxx是一個列表或者numpy的narray, 那么xxx里面可以是該DataFrame對象的列名,表示獲取指定的多個列,得到DataFrame對象
如果xxx是一個列表或者numpy的narray,那么這個xxx里面還可以是布爾值,并且其長度要和該DataFrame對象的行數相等,表示獲取對應的行數。對應為True的保留,為False的不要,也是得到DataFrame對象
舉個栗子
import pandas as pd
df = pd.DataFrame({"a": [1, 2, 3], "b": [11, 22, 33]})
# 只有第一個為True,因此被保留了下來
print(df[[True, False, False]])
"""
a b
0 1 11
"""
try:
# 但此時指定的4個布爾值
print(df[[True, False, False, False]])
except Exception as e:
print(e) # Item wrong length 4 instead of 3.
"""
告訴我們個數不匹配
所以上面之所以說了索引,就是因為在做運算的的時候可能導致布爾值的個數最終和DataFrame的行數不匹配
從而在篩選指定記錄的時候發生報錯
"""
如果是Series也是可以的
import pandas as pd
df = pd.DataFrame({"a": [1, 2, 3], "b": [11, 22, 33]})
flag = pd.Series([True, False, False])
print(df[flag])
"""
a b
0 1 11
"""
# 當然里面也可以是一個Series,當然這個Series不僅個數要匹配,索引也要匹配
# 我們知道df的索引是 0 1 2,那么該flag的索引也必須是0 1 2(但是順序不要求)
flag.index = [1, 2, 3]
try:
df[flag]
except Exception as e:
print(e)
# Unalignable boolean Series provided as indexer (index of the boolean Series and of the indexed object do not match).
"""
我們看到報了上面那個錯誤,意思我們傳遞了bool類型的Series對象,但是其索引和DataFrame的索引不匹配
"""
# 我們再改一下
flag.index = [1, 2, 0]
print(flag)
"""
1 True
2 False
0 False
dtype: bool
"""
print(df[flag])
"""
a b
1 2 22
"""
# 我們看到此時布爾值True對應的索引為1,那么篩選的就不再是df中的第一行了
# 而是索引為1的行,也就是第二行。
# 因此盡管對Series的索引的值有要求,但是對順序卻并沒有要求
# 所以這種情況下,篩選出來的數據可能就和我們想象的不一樣,明明第一個是True,為啥卻把DataFrame的第二行選出來了
# 原因就是,雖然第一個是True,但是它對應的索引是1
因此索引這個東西在定位數據的時候,會非常方便,因為我們可以直接通過索引去定位。但是在一些操作方面,我們關心的并不是它的索引,而是它的值,比如:s1 & s2,或者df[flag],這個時候我們只是對內部的布爾值感興趣,那么直接把s1、s2、flag這些變成numpy中的array之后,再去傳遞即可。此時就無需考慮索引啥的了。
5. 怎么給DataFrame添加字段呢?
給一個DataFrame添加一個字段,并附上初始值有以下幾種方式。
import pandas as pd
df = pd.DataFrame({"a": [1, 2, 3], "b": [11, 22, 33]})
# 可以給一個標量,然后會自動進行廣播
df["c"] = "xx"
# 也可以是一個列表,如果里面只有一個元素,那么和標量是等價的
df["d"] = "yy"
print(df)
"""
a b c d
0 1 11 xx yy
1 2 22 xx yy
2 3 33 xx yy
"""
# 如果是列表里面有多個值,那么個數必須和df的行數匹配
# 否則會報出ValueError: Length of values does not match length of index
df["e"] = ["x", "y", "z"]
print(df)
"""
a b c d e
0 1 11 xx yy x
1 2 22 xx yy y
2 3 33 xx yy z
"""
# 還有一種辦法是通過df.assign,這種辦法可以同時創建多個列
df = df[["a", "b"]]
df = df.assign(
# 這里指定接收一個參數的函數,這個參數就是整個df
# 通過關鍵字參數,那么參數名就是列名
c=lambda x: x["a"] + 1,
d=lambda x: x["b"] * 2,
e=lambda x: ["i", "j", "k"],
f=lambda x: "哼哼"
)
print(df)
"""
a b c d e f
0 1 11 2 22 i 哼哼
1 2 22 3 44 j 哼哼
2 3 33 4 66 k 哼哼
"""
給一個DataFrame添加一個字段,同樣存在索引的陷阱
import pandas as pd
df = pd.DataFrame({"a": [1, 2, 3], "b": [11, 22, 33]})
df["c"] = pd.Series(["x", "y", "z"], index=[0, 2, 3])
print(df)
"""
a b c
0 1 11 x
1 2 22 NaN
2 3 33 y
"""
原因無需我再多解釋,總而言之就是我們剛才說的那樣,如果我們只關心值,不關心索引,那么就不要傳遞Series對象,直接傳遞numpy中的array或者列表即可,這樣我們就根本不需要考慮索引對齊的問題。
傳遞一個一維序列是可以的,那么傳遞一個DataFrame對象會如何呢?
import pandas as pd
df = pd.DataFrame({"a": [1, 2, 3], "b": [11, 22, 33]})
df1 = pd.DataFrame({"x": ["aa", 22, None], "y": [">>", "^^", "YY"]})
try:
# 因為df1有兩個字段,這里我們只指定了一個
df["c"] = df1
except Exception as e:
print(e) # Wrong number of items passed 2, placement implies 1
# 我們知道df1["x"]是個Series,所以df["c"] = df1["x"]肯定沒有錯
# 但是df["c"] = df1[["x"]]呢? df1[["x"]]顯然是個DataFrame
df["c"] = df1[["x"]]
print(df)
"""
a b c
0 1 11 aa
1 2 22 22
2 3 33 None
"""
# 可以看到,如果DataFrame只有一個字段,那么等價于Series
# 最后,df["xx"] = xx 這種方式, 在xx是一維序列的前提下 完全等價于 df.loc[:, "xx"] = xx
# 但如果xx是一個DataFrame的話就不一樣了
df = pd.DataFrame({"a": [1, 2, 3], "b": [11, 22, 33]})
df1 = pd.DataFrame({"x": ["aa", 22, None], "y": [">>", "^^", "YY"]})
df.loc[:, "c"] = df1
print(df)
"""
a b c
0 1 11 NaN
1 2 22 NaN
2 3 33 NaN
"""
# 我們驚奇地發現它居然沒有報錯,但結果卻是NaN
# 我們rename一下
df1 = df1.rename(columns={"y": "c"})
df.loc[:, "c"] = df1
print(df)
"""
a b c
0 1 11 >>
1 2 22 ^^
2 3 33 YY
"""
# 因此我們發現在使用df.loc[:, "xx"] = df1的時候
# 會自動去找df1中列名為"xx"的列,如果找不到就為NaN
如果給DataFrame添加多個字段的話,除了assign之外,還有什么辦法呢?
import pandas as pd
df = pd.DataFrame({"a": [1, 2, 3], "b": [11, 22, 33]})
df1 = pd.DataFrame({"x": ["aa", 22, None], "y": [">>", "^^", "YY"]})
df[["c", "d"]] = df1
print(df)
"""
a b c d
0 1 11 aa >>
1 2 22 22 ^^
2 3 33 None YY
"""
# 這里可以要求列名不一致,但是個數必須要匹配
df = pd.DataFrame({"a": [1, 2, 3], "b": [11, 22, 33]})
df1 = pd.DataFrame({"x": ["aa", 22, None], "y": [">>", "^^", "YY"]})
# 但是對于loc來說,無法添加多個字段
# 添加一個字段是可以的,但是多個不行
try:
df.loc[:, ["c", "d"]] = df1
except Exception as e:
# loc表示篩選,而df的列中沒有"c"和"d"
# 即使是df.loc[:, ["c"]]也不可以,但是df.loc[:, "c"]是可以的
print(e) # "None of [Index(['c', 'd'], dtype='object')] are in the [columns]"
# 所以df[["c", "d"]] = df1,如果列c、d不存在, 那么會自動添加
# 但是對于df.loc[:, ["c", "d"]] = df1,如果c、d不存在,則報錯,注意:不是都不存在,而是只要有一個不存在就報錯
# 如果是指定了不存在的索引,暫時不會報錯,而是彈出一個警告
print(df.loc[[1, 11]])
"""
a b
1 2.0 22.0
11 NaN NaN
"""
# 我們看到指定了不存在的索引,那么自動為NaN
# 但同時會拋出一個FutureWarning:
"""
Passing list-likes to .loc or [] with any missing label will raise
KeyError in the future, you can use .reindex() as an alternative.
"""
# 意思是讓我們先reindex一下
所以如果想添加多個字段,可以直接通過df[["c1", "c2"]] = df1的方式,但是注意:右邊寫的df1,所以右邊需要也是一個DataFrame,并且兩者列數相等
import pandas as pd
df = pd.DataFrame({"a": [1, 2, 3], "b": [11, 22, 33]})
df1 = pd.DataFrame({"x": ["aa", 22, None], "y": [">>", "^^", "YY"]})
# 這里我們本意是想創建兩個字段,值都為None
# 但是很遺憾這樣不可以
try:
# 右邊的值也需要是一個DataFrame
df[["c", "d"]] = None
except Exception as e:
# 我們看到這里也同樣報出了相應的錯誤
# 因此只有當右邊的值是DataFrame的時候,df[["c", "d"]]才能具備創建新字段的能力
print(e) # "None of [Index(['c', 'd'], dtype='object')] are in the [columns]"
# 如果想創建多個新字段,并且還希望通過廣播的方式賦上同一個值,那么上面做法是行不通的
# 解決辦法是一個字段一個字段的創建,這樣百分之百是沒有任何問題的,既可以df["c"]也可以df.loc[:, "c"]
# 但是也可以通過我們之前說的assign
df = df.assign(
c=lambda x: None,
d=lambda x: None,
)
print(df)
"""
a b c d
0 1 11 None None
1 2 22 None None
2 3 33 None None
"""
# 除此之外,還有一個insert方法
# 這個方法接收:插入的位置、列名、值
# 比如我想在列c的后面插入一個新列age,值全部是18,該怎么做呢?
df.insert(df.columns.get_loc("c") + 1, "age", 18)
print(df)
"""
a b c age d
0 1 11 None 18 None
1 2 22 None 18 None
2 3 33 None 18 None
"""
# 我們看到insert這個方法是在本地進行操作的
# 關鍵是第一個參數,我們希望插在c的后面,那么就必須獲取c所在的索引,當然也可以直接數出來
# 通過columns.get_loc即可獲取,然后再加上1即可
6. ValueError: cannot compute isin with a duplicate axis.
這個錯誤當初也是把我搞懵逼了半天,在復現這個異常之前,我們先來聊聊非常常用的isin
isin我們一般是對Series對象使用,判斷這個序列中每一個元素是不是在另一個序列里面,下面舉例說明:
import pandas as pd
s = pd.Series(["a", "b", "c", "d"])
print(s.isin(["a", "c", "e"]))
"""
0 True
1 False
2 True
3 False
dtype: bool
"""
這個方法是我們經常使用的,但是你對DataFrame使用過isin嗎?我們有時候需要判斷兩個序列,看這兩個序列中的值是否在另外兩個序列里面。
import pandas as pd
df1 = pd.DataFrame({"x": ["a", "b", "c", "d"], "y": [1, 2, 3, 4]})
df2 = pd.DataFrame({"x": ["a", "B", "c", "D"], "y": [1, 2, 4, 3]})
print(df1)
"""
x y
0 a 1
1 b 2
2 c 3
3 d 4
"""
print(df2)
"""
x y
0 a 1
1 B 2
2 c 4
3 D 3
"""
print(df1[["x"]].isin(df2))
# DataFrame中有兩列,所以是兩列布爾值
"""
x y
0 True True
1 False True
2 True False
3 False False
"""
# 我們來分析一下,對于df1來說,前兩行肯定是沒有問題的
# 但是第三行有點詭異,我們df1的第三行的y列是3,顯然3是在df2的y列當中啊,為什么是False
# 同理第4行,"d"不在df2的x列中我們知道,但是y列的4很明顯在df2的y列當中,為什么是False
估計有人猜到了,那就是對DataFrame使用isin的時候,多個列之間并不是獨立的。事實上,DataFrame使用isin也是根據索引來的,我們舉個栗子
import pandas as pd
df1 = pd.DataFrame({"x": ["a", "b", "c", "d"], "y": [1, 2, 3, 4]})
df2 = pd.DataFrame({"x": ["a", "b", "c", "d"], "y": [1, 2, 3, 4]})
# 兩個一模一樣的DataFrame對象
print(df1.isin(df2))
"""
x y
0 True True
1 True True
2 True True
3 True True
"""
# 結果沒問題,但是我們將df2的索引改變一下
df2.index = [0, 1, 3, 2]
print(df1.isin(df2))
"""
x y
0 True True
1 True True
2 False False
3 False False
"""
# 此時我們就看到端倪了,對于DataFrame對象來講,isin是判斷對應索引的字段的值是否相同
但是問題又來了,因為這樣顯然不是我們期望的結果。因為即使df2中存在,但如果索引對不上的話也沒有任何意義,因此我們可以手動設置索引。
import pandas as pd
df1 = pd.DataFrame({"x": ["a", "b", "c", "d"], "y": [1, 2, 3, 4]})
df2 = pd.DataFrame({"x": ["a", "b", "d", "c"], "y": [1, 2, 4, 3]})
# 我們將x和y設置為索引不就行了,加上drop=False表示設置索引的同時,還作為列
df1 = df1.set_index(["x", "y"], drop=False)
df2 = df2.set_index(["x", "y"], drop=False)
print(df1)
"""
x y
x y
a 1 a 1
b 2 b 2
c 3 c 3
d 4 d 4
"""
print(df2)
"""
x y
x y
a 1 a 1
b 2 b 2
d 4 d 4
c 3 c 3
"""
print(df1.isin(df2))
"""
x y
x y
a 1 True True
b 2 True True
c 3 True True
d 4 True True
"""
# 在通過all(axis=1)即可找到滿足條件的值
print(df1.isin(df2).all(axis=1).values) # [ True True True True]
# 我們看到此時根據索引去找,就能夠準確的定位了
# 不過細心的人可能已經發現了,這個索引是由x和y兩列得到的,事實上索引如果匹配上了,那么值一定是相等的
# 所以此時就沒必要在進行對比了
# 是的,所以我們可以換一種方法
df1 = pd.DataFrame({"x": ["a", "b", "c", "d"], "y": [1, 2, 3, 4]})
df2 = pd.DataFrame({"x": ["a", "b", "d", "c"], "y": [1, 2, 4, 3]})
# pandas中有一個Index類,Series和DataFrame的索引就是Index類型
# 當然Index分為好幾種,但是它們繼承自Index
print(type(df1.index)) # <class 'pandas.core.indexes.range.RangeIndex'>
# 根據x和y兩列創建Index對象
index1 = pd.Index(df1[["x", "y"]])
index2 = pd.Index(df2[["x", "y"]])
print(index1) # Index([('a', 1), ('b', 2), ('c', 3), ('d', 4)], dtype='object')
print(index2) # Index([('a', 1), ('b', 2), ('d', 4), ('c', 3)], dtype='object')
# Index對象可以像集合一樣,取并集、交集,當然此時我們可以直接使用isin
# 因為它們整體變成了一個元組,也就是說,此時是一個一維序列,對于一維序列可以直接使用isin
# 直接返回一個numpy中的array
print(index1.isin(index2)) # [ True True True True]
然而這么做有一個弊端,沒錯,我要復現我們上面的異常了
import pandas as pd
df1 = pd.DataFrame({"x": ["a", "b", "c", "d"], "y": [1, 2, 3, 4]})
df2 = pd.DataFrame({"x": ["a", "a", "c", "d"], "y": [1, 1, 3, 4]})
# 我們將x和y設置為索引不就行了,加上drop=False表示設置索引的同時,還作為列
df1 = df1.set_index(["x", "y"], drop=False)
df2 = df2.set_index(["x", "y"], drop=False)
try:
print(df1.isin(df2))
except Exception as e:
print(e) # cannot compute isin with a duplicate axis.
# 我們對一個DataFrame使用isin,那么要求isin里面的DataFrame的索引是不可以重復的,否則就會報出上面這個錯誤
# 解決辦法是使用pd.Index
print(pd.Index(df1[["x", "y"]]).isin(pd.Index(df2[["x", "y"]]))) # [ True False True True]
# 然鵝,我記得pd.Index這種做法也不保險
# 由于索引的特殊性,好像這種情況我記得也報錯,但是目前沒有
# 因此最穩妥的辦法是再轉成Series
s1 = pd.Series(pd.Index(df1[["x", "y"]]))
s2 = pd.Series(pd.Index(df2[["x", "y"]]))
print(s1)
"""
0 (a, 1)
1 (b, 2)
2 (c, 3)
3 (d, 4)
dtype: object
"""
print(s2)
"""
0 (a, 1)
1 (a, 1)
2 (c, 3)
3 (d, 4)
dtype: object
"""
print(s1.isin(s2))
"""
0 True
1 False
2 True
3 True
dtype: bool
"""
# 這種做法是百分之百沒有問題的
# 忘記說了,df1.isin(df2)的時候,兩個列的名稱一定要對應
df1 = pd.DataFrame({"x": ["a", "b", "c", "d"], "y": [1, 2, 3, 4]})
df2 = pd.DataFrame({"a": ["a", "a", "c", "d"], "y": [1, 1, 3, 4]})
print(df1.isin(df2))
"""
x y
0 False True
1 False False
2 False True
3 False True
"""
# 由于df2中沒有x這一列,因此相當于NaN,所以結果為False
print(df1[["y"]].isin(df2))
"""
y
0 True
1 False
2 True
3 True
"""
# 會自動找df2中名稱為y的列進行比較,因此記得注意列名
# 當然由于df1.isin(df2)在索引方面的局限性,我們一般也不會使用這種方法
# 而是會將DataFrame的每一個字段的值拼接成一個元組,整體得到一個Series對象
# 然后對Series對象使用isin,這是最正確的做法
7. ValueError: cannot set a frame with no defined index and a scalar
這個錯誤不是很常見,我們來看一下。
import pandas as pd
df = pd.DataFrame({"a": [1, 1, 1, 1], "b": [1, 1, 1, 1]})
df.loc[df["a"] > 2, "c"] = 1
print(df)
"""
a b c
0 1 1 NaN
1 1 1 NaN
2 1 1 NaN
3 1 1 NaN
"""
我們將df["a"] > 2的記錄選出來,然后同時創建"c"這一列,并設置對應的記錄為1。如果不滿足條件,那么會自動為NaN,而我們沒有滿足條件的記錄,所以全部為NaN
import pandas as pd
df = pd.DataFrame({"a": [1, 1, 1, 1], "b": [1, 1, 1, 1]})
df.loc[:, "c"] = 1
print(df)
"""
a b c
0 1 1 1
1 1 1 1
2 1 1 1
3 1 1 1
"""
上面這種賦值方式也是可以的,我們之前說,對于一維序列,df["xx"]等價于df.loc[:, "xx"],但實際上還是有點區別的,那就是后者要求DataFrame不可以為空
import pandas as pd
df = pd.DataFrame({"a": [], "b": []})
print(df)
"""
Empty DataFrame
Columns: [a, b]
Index: []
"""
try:
df.loc[:, "c"] = 1
except Exception as e:
print(e) # cannot set a frame with no defined index and a scalar
# 空DataFrame的話,只能用df["c"] = 1的方式
df["c"] = 1
print(df)
"""
Empty DataFrame
Columns: [a, b, c]
Index: []
"""
8. ValueError: If using all scalar values, you must pass an index
這個錯誤應該遇見的比較少,我們看看這種錯誤是怎么發生的。
import pandas as pd
# 我們說通過字典構建DataFrame,value應該是序列,不應該是一個標量
try:
df = pd.DataFrame({"a": 123, "b": None})
except Exception as e:
print(e) # If using all scalar values, you must pass an index
# 如果傳遞標量的話,那么應該同時指定一個index, index是只有一個元素的列表,里面是一個索引
df = pd.DataFrame({"a": 123, "b": None}, index=["索引"])
print(df)
"""
a b
索引 123 None
"""
有待發掘。。。。
總結
以上是生活随笔為你收集整理的pandas中的那些让人有点懵逼的异常(坑向)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [译]Java 垃圾回收介绍
- 下一篇: oracle修改统计信息收集时间以及窗口