import pandas as pd
def normalize_dtypes(ldf, rdf):
"""Normalize the dtypes of columns with same name from two DataFrames.
Parameters
----------
ldf : pd.DataFrame
The left DataFrame.
rdf : pd.DataFrame
The right DataFrame.
Returns
-------
Tuple[pd.DataFrame, pd.DataFrame]
The left and right DataFrames with normalized common columns dtypes.
Notes
-----
If a column name from one of the dataframes is named differently on the
other, you will need to rename the column before calling this function.
"""
ldf = ldf.convert_dtypes()
rdf = rdf.convert_dtypes()
common_cols = ldf.columns.intersection(rdf.columns)
for col in common_cols:
ldtype = ldf[col].dtype.name
rdtype = rdf[col].dtype.name
if ldtype != rdtype:
if ldtype == 'string':
try:
ldf[col] = ldf[col].astype(rdtype)
except Exception: # noqa
if 'Float' in rdtype and ldf[col].str.split(
'.').str.len().max() == 1:
rdf[col] = rdf[col].round(0).astype(int)
rdf[col] = rdf[col].astype(ldtype)
if ldf[col].str.len().nunique() == 1:
if rdf[col].str.len().max() > ldf[col].str.len().max():
rdf[col] = rdf[col].str[:ldf[col].str.len().max()]
else:
maxlen = max([ldf[col].str.len().max(),
rdf[col].str.len().max()])
_rdf1 = rdf[col].str.zfill(maxlen)
_ldf1 = ldf[col].str.zfill(maxlen)
_rdf2 = rdf[col].str.rjust('0', maxlen)
_ldf2 = ldf[col].str.rjust('0', maxlen)
c1 = _rdf1.isin(_ldf1).count()
c2 = _rdf2.isin(_ldf2).count()
rdf[col] = _rdf1 if c1 > c2 else _rdf2
elif rdtype == 'string':
try:
rdf[col] = rdf[col].astype(ldtype)
except Exception: # noqa
if 'Float' in ldtype and rdf[col].str.split(
'.').str.len().max() == 1:
ldf[col] = ldf[col].round(0).astype(int)
ldf[col] = ldf[col].astype(rdtype)
if rdf[col].str.len().nunique() == 1:
if ldf[col].str.len().max() > rdf[col].str.len().max():
ldf[col] = ldf[col].str[:rdf[col].str.len().max()]
else:
maxlen = max([ldf[col].str.len().max(),
rdf[col].str.len().max()])
_rdf1 = rdf[col].str.zfill(maxlen)
_ldf1 = ldf[col].str.zfill(maxlen)
_rdf2 = rdf[col].str.rjust('0', maxlen)
_ldf2 = ldf[col].str.rjust('0', maxlen)
c1 = _ldf1.isin(_rdf1).count()
c2 = _ldf2.isin(_rdf2).count()
ldf[col] = _ldf1 if c1 > c2 else _ldf2
elif 'Float' in ldtype and 'Int' in rdtype:
ldf[col] = ldf[col].round(0).astype(rdtype)
elif 'Float' in rdtype and 'Int' in ldtype:
rdf[col] = rdf[col].round(0).astype(ldtype)
return ldf, rdf
1条答案
按热度按时间ryevplcw1#
可能原因1:检查不匹配的键列数据类型
merge
返回空帧的一个可能原因是weatherdf
和galdf
的键列的数据类型不匹配。要确定是否是这种情况,可以尝试以下操作:上面的代码将打印具有不匹配数据类型的键列的名称。
如果是这种情况,那么您可以使用以下策略之一来解决问题。
解决方案1(更简单的解决方案)
解决此问题的最简单方法是手动将列的数据类型更改为通用类型。
例如,假设
"Store No"
列在weatherdf
中表示为string
(或object
),在galdf
中表示为integer
。在这种情况下,您可以在尝试合并两个 Dataframe 之前将"Store No"
从weatherdf
转换为整数:解决方案2(不推荐)
解决这个问题的一个方法是,以更程式化的方式,建立一个函数,在两个数据框中寻找具有共同名称的栏,并尝试将它们转换成共同的资料类型。以下是这种函数的一个撰写不佳的实作:
下面是一个尝试合并
weatherdf
和galdf
的示例,分别使用和不使用normalize_dtypes
函数:不使用
normalize_dtypes
函数:使用
normalize_dtypes
函数:可能原因2:两个数据框之间没有公共值
您绝对确定
galdf
和weatherdf
上有共同的值吗?您可以尝试使用较小的列集作为
on
参数,并查看是否返回非空 Dataframe 。这可以帮助您查明导致merge
返回空 Dataframe 的列。例如:在上面的例子中,我们已经从合并操作中删除了
"Hour"
列。这样做,合并返回了一些行。这意味着由于"Hour"
列中的一些不匹配的值,合并可能返回了一个空的 Dataframe 。