Scala——如何从原始数据创建映射以计算不同的值
Scala新手,尝试读取输入的原始数据以生成多个字段上带有groupBy的映射 原始数据样本:Scala——如何从原始数据创建映射以计算不同的值,scala,Scala,Scala新手,尝试读取输入的原始数据以生成多个字段上带有groupBy的映射 原始数据样本: date,uid,site,success 2014-07-14,userA,google,1 2014-07-14,userB,google,1 2014-07-14,userC,yahoo,1 2014-07-14,userD,facebook,1 我想报告每个站点在每个日期的不同用户数 2014-07-14,google,2 2014-07-14,yahoo,1 2014-07-14,face
date,uid,site,success
2014-07-14,userA,google,1
2014-07-14,userB,google,1
2014-07-14,userC,yahoo,1
2014-07-14,userD,facebook,1
我想报告每个站点在每个日期的不同用户数
2014-07-14,google,2
2014-07-14,yahoo,1
2014-07-14,facebook,1
为此,我尝试在日期和站点字段上使用groupBy,其值为uid。一旦我有了这个数据结构,我就可以迭代映射并计算不同的映射值。
有人能告诉我如何生成数据结构吗
谢谢 为了清晰起见,放弃标题行,可能的实现方式如下:
val text = """2014-07-14,userA,google,1
|2014-07-14,userA,google,1
|2014-07-14,userB,google,1
|2014-07-14,userC,yahoo,1
|2014-07-16,userC,yahoo,1
|2014-07-14,userD,facebook,1
|2014-07-14,userE,facebook,1
|""".stripMargin
val uniqueUsersByDateSite: Map[(String, String), Int] = text.lines.map {
line =>
val tokens = line.split(",")
(tokens(0), tokens(1), tokens(2))
}.toSet.groupBy {
tuple: (String, String, String) =>
(tuple._1, tuple._3)
}.mapValues {
_.size
}
通过创建一组元组(日期、uid、站点)
,我们为特定日期的站点的每个唯一用户收集一个项
然后,groupBy
方法按(日期,站点)
收集,将同一日期和站点的N个项目转换为一个地图条目,其中包含与相应日期和站点的唯一用户数相对应的项目数
最终的mapValue
方法实现了预期的结果:
Map((2014-07-16,yahoo) -> 1, (2014-07-14,facebook) -> 2, (2014-07-14,google) -> 2, (2014-07-14,yahoo) -> 1)
我希望我理解正确。这里有一个完整的例子
case class Data(date: String, uid: String, site: String, success: Int)
val sampleData = List(
Data("2014-07-14","userA","google",1),
Data("2014-07-14","userA","google",1),
Data("2014-07-14","userB","google",1),
Data("2014-07-14","userC","yahoo",1),
Data("2014-07-14","userD","facebook",1)
)
sampleData.groupBy(_.date).map
{case (date, datelist) => (date, datelist.groupBy(_.site).map
{case (site, sitelist) => (site, sitelist.groupBy(_.uid).size)})}
输出是:Map(2014-07-14->Map(google->2,yahoo->1,facebook->1))
基本上,每个日期都有一张地图,其中包含不同用户对站点的访问。请注意,来自userA
的2次访问计数为1
sitelist.groupBy(_.uid).size
按uid
统计不同的访问次数
编辑是的,无需额外的数据结构即可编辑。现在只需要处理数组的索引
val fileText = """2014-07-14,userA,google,1
2014-07-14,userA,google,1
2014-07-14,userA,google,1
2014-07-14,userB,google,1
2014-07-14,userC,yahoo,1
2014-07-14,userD,facebook,1""".stripMargin
fileText.lines.map(_.split(",")).toList.groupBy(_(0)).map
{case (date, datelist) => (date, datelist.groupBy(_(2)).map
{case (site, sitelist) => (site, sitelist.groupBy(_(1)).size)})}
在@Kigyo发布的答案看起来不错,但我认为你可以稍微扩展一下: 因此,假设此数据结构:
case class Data(date: String, uid: String, site: String, success: Int)
val sampleData = List(
Data("2014-07-14","userA","google",1),
Data("2014-07-14","userA","google",1),
Data("2014-07-14","userB","google",1),
Data("2014-07-14","userC","yahoo",1),
Data("2014-07-14","userD","facebook",1)
)
您可以通过以下方式实现您的目标:
list.groupBy((_.date , _.site)).collect{ case (a , b : List[Data]) =>(a._1 , a._2 , b.map(_.success).sum) } ;
它返回一个Tuple3列表,就像您想要的那样1。你的输入数据有多大?2.您以后是否需要跨日期统计不同的用户数?每天大约有一百万行,并且需要跨日期统计不同的用户数。谢谢是的,这取决于@user2727704想要什么样的数据结构。我还假设
success
的数量与此无关,因为不同用户的数量与此无关。除了b.map(u.success)。sum之外,还有其他方法可以在uid上应用count distinct,因为我可能并不总是有一个success字段。谢谢如果您希望“success”字段像date和site一样使用(充当过滤器),最好的方法是将其包含在第一个元组中(在groupby中)。非常感谢。。从你的回答中学到了一些关于Scala的新东西。谢谢Kigyo,肯定回答了我的问题。由于我将解析外部文件的原始数据,构造数据对象是否会增加额外的开销?还有其他选择吗?